1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * M66592 UDC (USB gadget) |
4 | * |
5 | * Copyright (C) 2006-2007 Renesas Solutions Corp. |
6 | * |
7 | * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/io.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/err.h> |
17 | #include <linux/usb/ch9.h> |
18 | #include <linux/usb/gadget.h> |
19 | |
20 | #include "m66592-udc.h" |
21 | |
22 | MODULE_DESCRIPTION("M66592 USB gadget driver" ); |
23 | MODULE_LICENSE("GPL" ); |
24 | MODULE_AUTHOR("Yoshihiro Shimoda" ); |
25 | MODULE_ALIAS("platform:m66592_udc" ); |
26 | |
27 | #define DRIVER_VERSION "21 July 2009" |
28 | |
29 | static const char udc_name[] = "m66592_udc" ; |
30 | static const char *m66592_ep_name[] = { |
31 | "ep0" , "ep1" , "ep2" , "ep3" , "ep4" , "ep5" , "ep6" , "ep7" |
32 | }; |
33 | |
34 | static void disable_controller(struct m66592 *m66592); |
35 | static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req); |
36 | static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req); |
37 | static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, |
38 | gfp_t gfp_flags); |
39 | |
40 | static void transfer_complete(struct m66592_ep *ep, |
41 | struct m66592_request *req, int status); |
42 | |
43 | /*-------------------------------------------------------------------------*/ |
44 | static inline u16 get_usb_speed(struct m66592 *m66592) |
45 | { |
46 | return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST); |
47 | } |
48 | |
49 | static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum, |
50 | unsigned long reg) |
51 | { |
52 | u16 tmp; |
53 | |
54 | tmp = m66592_read(m66592, M66592_INTENB0); |
55 | m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, |
56 | M66592_INTENB0); |
57 | m66592_bset(m66592, (1 << pipenum), reg); |
58 | m66592_write(m66592, val: tmp, M66592_INTENB0); |
59 | } |
60 | |
61 | static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum, |
62 | unsigned long reg) |
63 | { |
64 | u16 tmp; |
65 | |
66 | tmp = m66592_read(m66592, M66592_INTENB0); |
67 | m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, |
68 | M66592_INTENB0); |
69 | m66592_bclr(m66592, (1 << pipenum), reg); |
70 | m66592_write(m66592, val: tmp, M66592_INTENB0); |
71 | } |
72 | |
73 | static void m66592_usb_connect(struct m66592 *m66592) |
74 | { |
75 | m66592_bset(m66592, M66592_CTRE, M66592_INTENB0); |
76 | m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, |
77 | M66592_INTENB0); |
78 | m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); |
79 | |
80 | m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); |
81 | } |
82 | |
83 | static void m66592_usb_disconnect(struct m66592 *m66592) |
84 | __releases(m66592->lock) |
85 | __acquires(m66592->lock) |
86 | { |
87 | m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0); |
88 | m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, |
89 | M66592_INTENB0); |
90 | m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); |
91 | m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); |
92 | |
93 | m66592->gadget.speed = USB_SPEED_UNKNOWN; |
94 | spin_unlock(lock: &m66592->lock); |
95 | m66592->driver->disconnect(&m66592->gadget); |
96 | spin_lock(lock: &m66592->lock); |
97 | |
98 | disable_controller(m66592); |
99 | INIT_LIST_HEAD(list: &m66592->ep[0].queue); |
100 | } |
101 | |
102 | static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) |
103 | { |
104 | u16 pid = 0; |
105 | unsigned long offset; |
106 | |
107 | if (pipenum == 0) |
108 | pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID; |
109 | else if (pipenum < M66592_MAX_NUM_PIPE) { |
110 | offset = get_pipectr_addr(pipenum); |
111 | pid = m66592_read(m66592, offset) & M66592_PID; |
112 | } else |
113 | pr_err("unexpect pipe num (%d)\n" , pipenum); |
114 | |
115 | return pid; |
116 | } |
117 | |
118 | static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, |
119 | u16 pid) |
120 | { |
121 | unsigned long offset; |
122 | |
123 | if (pipenum == 0) |
124 | m66592_mdfy(m66592, val: pid, M66592_PID, M66592_DCPCTR); |
125 | else if (pipenum < M66592_MAX_NUM_PIPE) { |
126 | offset = get_pipectr_addr(pipenum); |
127 | m66592_mdfy(m66592, val: pid, M66592_PID, offset); |
128 | } else |
129 | pr_err("unexpect pipe num (%d)\n" , pipenum); |
130 | } |
131 | |
132 | static inline void pipe_start(struct m66592 *m66592, u16 pipenum) |
133 | { |
134 | control_reg_set_pid(m66592, pipenum, M66592_PID_BUF); |
135 | } |
136 | |
137 | static inline void pipe_stop(struct m66592 *m66592, u16 pipenum) |
138 | { |
139 | control_reg_set_pid(m66592, pipenum, M66592_PID_NAK); |
140 | } |
141 | |
142 | static inline void pipe_stall(struct m66592 *m66592, u16 pipenum) |
143 | { |
144 | control_reg_set_pid(m66592, pipenum, M66592_PID_STALL); |
145 | } |
146 | |
147 | static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum) |
148 | { |
149 | u16 ret = 0; |
150 | unsigned long offset; |
151 | |
152 | if (pipenum == 0) |
153 | ret = m66592_read(m66592, M66592_DCPCTR); |
154 | else if (pipenum < M66592_MAX_NUM_PIPE) { |
155 | offset = get_pipectr_addr(pipenum); |
156 | ret = m66592_read(m66592, offset); |
157 | } else |
158 | pr_err("unexpect pipe num (%d)\n" , pipenum); |
159 | |
160 | return ret; |
161 | } |
162 | |
163 | static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum) |
164 | { |
165 | unsigned long offset; |
166 | |
167 | pipe_stop(m66592, pipenum); |
168 | |
169 | if (pipenum == 0) |
170 | m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR); |
171 | else if (pipenum < M66592_MAX_NUM_PIPE) { |
172 | offset = get_pipectr_addr(pipenum); |
173 | m66592_bset(m66592, M66592_SQCLR, offset); |
174 | } else |
175 | pr_err("unexpect pipe num(%d)\n" , pipenum); |
176 | } |
177 | |
178 | static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum) |
179 | { |
180 | u16 tmp; |
181 | int size; |
182 | |
183 | if (pipenum == 0) { |
184 | tmp = m66592_read(m66592, M66592_DCPCFG); |
185 | if ((tmp & M66592_CNTMD) != 0) |
186 | size = 256; |
187 | else { |
188 | tmp = m66592_read(m66592, M66592_DCPMAXP); |
189 | size = tmp & M66592_MAXP; |
190 | } |
191 | } else { |
192 | m66592_write(m66592, val: pipenum, M66592_PIPESEL); |
193 | tmp = m66592_read(m66592, M66592_PIPECFG); |
194 | if ((tmp & M66592_CNTMD) != 0) { |
195 | tmp = m66592_read(m66592, M66592_PIPEBUF); |
196 | size = ((tmp >> 10) + 1) * 64; |
197 | } else { |
198 | tmp = m66592_read(m66592, M66592_PIPEMAXP); |
199 | size = tmp & M66592_MXPS; |
200 | } |
201 | } |
202 | |
203 | return size; |
204 | } |
205 | |
206 | static inline void pipe_change(struct m66592 *m66592, u16 pipenum) |
207 | { |
208 | struct m66592_ep *ep = m66592->pipenum2ep[pipenum]; |
209 | unsigned short mbw; |
210 | |
211 | if (ep->use_dma) |
212 | return; |
213 | |
214 | m66592_mdfy(m66592, val: pipenum, M66592_CURPIPE, offset: ep->fifosel); |
215 | |
216 | ndelay(450); |
217 | |
218 | if (m66592->pdata->on_chip) |
219 | mbw = M66592_MBW_32; |
220 | else |
221 | mbw = M66592_MBW_16; |
222 | |
223 | m66592_bset(m66592, mbw, ep->fifosel); |
224 | } |
225 | |
226 | static int pipe_buffer_setting(struct m66592 *m66592, |
227 | struct m66592_pipe_info *info) |
228 | { |
229 | u16 bufnum = 0, buf_bsize = 0; |
230 | u16 pipecfg = 0; |
231 | |
232 | if (info->pipe == 0) |
233 | return -EINVAL; |
234 | |
235 | m66592_write(m66592, val: info->pipe, M66592_PIPESEL); |
236 | |
237 | if (info->dir_in) |
238 | pipecfg |= M66592_DIR; |
239 | pipecfg |= info->type; |
240 | pipecfg |= info->epnum; |
241 | switch (info->type) { |
242 | case M66592_INT: |
243 | bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT); |
244 | buf_bsize = 0; |
245 | break; |
246 | case M66592_BULK: |
247 | /* isochronous pipes may be used as bulk pipes */ |
248 | if (info->pipe >= M66592_BASE_PIPENUM_BULK) |
249 | bufnum = info->pipe - M66592_BASE_PIPENUM_BULK; |
250 | else |
251 | bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC; |
252 | |
253 | bufnum = M66592_BASE_BUFNUM + (bufnum * 16); |
254 | buf_bsize = 7; |
255 | pipecfg |= M66592_DBLB; |
256 | if (!info->dir_in) |
257 | pipecfg |= M66592_SHTNAK; |
258 | break; |
259 | case M66592_ISO: |
260 | bufnum = M66592_BASE_BUFNUM + |
261 | (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16; |
262 | buf_bsize = 7; |
263 | break; |
264 | } |
265 | |
266 | if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) { |
267 | pr_err("m66592 pipe memory is insufficient\n" ); |
268 | return -ENOMEM; |
269 | } |
270 | |
271 | m66592_write(m66592, val: pipecfg, M66592_PIPECFG); |
272 | m66592_write(m66592, val: (buf_bsize << 10) | (bufnum), M66592_PIPEBUF); |
273 | m66592_write(m66592, val: info->maxpacket, M66592_PIPEMAXP); |
274 | if (info->interval) |
275 | info->interval--; |
276 | m66592_write(m66592, val: info->interval, M66592_PIPEPERI); |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static void pipe_buffer_release(struct m66592 *m66592, |
282 | struct m66592_pipe_info *info) |
283 | { |
284 | if (info->pipe == 0) |
285 | return; |
286 | |
287 | if (is_bulk_pipe(info->pipe)) { |
288 | m66592->bulk--; |
289 | } else if (is_interrupt_pipe(info->pipe)) |
290 | m66592->interrupt--; |
291 | else if (is_isoc_pipe(info->pipe)) { |
292 | m66592->isochronous--; |
293 | if (info->type == M66592_BULK) |
294 | m66592->bulk--; |
295 | } else |
296 | pr_err("ep_release: unexpect pipenum (%d)\n" , |
297 | info->pipe); |
298 | } |
299 | |
300 | static void pipe_initialize(struct m66592_ep *ep) |
301 | { |
302 | struct m66592 *m66592 = ep->m66592; |
303 | unsigned short mbw; |
304 | |
305 | m66592_mdfy(m66592, val: 0, M66592_CURPIPE, offset: ep->fifosel); |
306 | |
307 | m66592_write(m66592, M66592_ACLRM, offset: ep->pipectr); |
308 | m66592_write(m66592, val: 0, offset: ep->pipectr); |
309 | m66592_write(m66592, M66592_SQCLR, offset: ep->pipectr); |
310 | if (ep->use_dma) { |
311 | m66592_mdfy(m66592, val: ep->pipenum, M66592_CURPIPE, offset: ep->fifosel); |
312 | |
313 | ndelay(450); |
314 | |
315 | if (m66592->pdata->on_chip) |
316 | mbw = M66592_MBW_32; |
317 | else |
318 | mbw = M66592_MBW_16; |
319 | |
320 | m66592_bset(m66592, mbw, ep->fifosel); |
321 | } |
322 | } |
323 | |
324 | static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, |
325 | const struct usb_endpoint_descriptor *desc, |
326 | u16 pipenum, int dma) |
327 | { |
328 | if ((pipenum != 0) && dma) { |
329 | if (m66592->num_dma == 0) { |
330 | m66592->num_dma++; |
331 | ep->use_dma = 1; |
332 | ep->fifoaddr = M66592_D0FIFO; |
333 | ep->fifosel = M66592_D0FIFOSEL; |
334 | ep->fifoctr = M66592_D0FIFOCTR; |
335 | ep->fifotrn = M66592_D0FIFOTRN; |
336 | } else if (!m66592->pdata->on_chip && m66592->num_dma == 1) { |
337 | m66592->num_dma++; |
338 | ep->use_dma = 1; |
339 | ep->fifoaddr = M66592_D1FIFO; |
340 | ep->fifosel = M66592_D1FIFOSEL; |
341 | ep->fifoctr = M66592_D1FIFOCTR; |
342 | ep->fifotrn = M66592_D1FIFOTRN; |
343 | } else { |
344 | ep->use_dma = 0; |
345 | ep->fifoaddr = M66592_CFIFO; |
346 | ep->fifosel = M66592_CFIFOSEL; |
347 | ep->fifoctr = M66592_CFIFOCTR; |
348 | ep->fifotrn = 0; |
349 | } |
350 | } else { |
351 | ep->use_dma = 0; |
352 | ep->fifoaddr = M66592_CFIFO; |
353 | ep->fifosel = M66592_CFIFOSEL; |
354 | ep->fifoctr = M66592_CFIFOCTR; |
355 | ep->fifotrn = 0; |
356 | } |
357 | |
358 | ep->pipectr = get_pipectr_addr(pipenum); |
359 | ep->pipenum = pipenum; |
360 | ep->ep.maxpacket = usb_endpoint_maxp(epd: desc); |
361 | m66592->pipenum2ep[pipenum] = ep; |
362 | m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; |
363 | INIT_LIST_HEAD(list: &ep->queue); |
364 | } |
365 | |
366 | static void m66592_ep_release(struct m66592_ep *ep) |
367 | { |
368 | struct m66592 *m66592 = ep->m66592; |
369 | u16 pipenum = ep->pipenum; |
370 | |
371 | if (pipenum == 0) |
372 | return; |
373 | |
374 | if (ep->use_dma) |
375 | m66592->num_dma--; |
376 | ep->pipenum = 0; |
377 | ep->busy = 0; |
378 | ep->use_dma = 0; |
379 | } |
380 | |
381 | static int alloc_pipe_config(struct m66592_ep *ep, |
382 | const struct usb_endpoint_descriptor *desc) |
383 | { |
384 | struct m66592 *m66592 = ep->m66592; |
385 | struct m66592_pipe_info info; |
386 | int dma = 0; |
387 | int *counter; |
388 | int ret; |
389 | |
390 | ep->ep.desc = desc; |
391 | |
392 | BUG_ON(ep->pipenum); |
393 | |
394 | switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { |
395 | case USB_ENDPOINT_XFER_BULK: |
396 | if (m66592->bulk >= M66592_MAX_NUM_BULK) { |
397 | if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { |
398 | pr_err("bulk pipe is insufficient\n" ); |
399 | return -ENODEV; |
400 | } else { |
401 | info.pipe = M66592_BASE_PIPENUM_ISOC |
402 | + m66592->isochronous; |
403 | counter = &m66592->isochronous; |
404 | } |
405 | } else { |
406 | info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk; |
407 | counter = &m66592->bulk; |
408 | } |
409 | info.type = M66592_BULK; |
410 | dma = 1; |
411 | break; |
412 | case USB_ENDPOINT_XFER_INT: |
413 | if (m66592->interrupt >= M66592_MAX_NUM_INT) { |
414 | pr_err("interrupt pipe is insufficient\n" ); |
415 | return -ENODEV; |
416 | } |
417 | info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt; |
418 | info.type = M66592_INT; |
419 | counter = &m66592->interrupt; |
420 | break; |
421 | case USB_ENDPOINT_XFER_ISOC: |
422 | if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { |
423 | pr_err("isochronous pipe is insufficient\n" ); |
424 | return -ENODEV; |
425 | } |
426 | info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous; |
427 | info.type = M66592_ISO; |
428 | counter = &m66592->isochronous; |
429 | break; |
430 | default: |
431 | pr_err("unexpect xfer type\n" ); |
432 | return -EINVAL; |
433 | } |
434 | ep->type = info.type; |
435 | |
436 | info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; |
437 | info.maxpacket = usb_endpoint_maxp(epd: desc); |
438 | info.interval = desc->bInterval; |
439 | if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) |
440 | info.dir_in = 1; |
441 | else |
442 | info.dir_in = 0; |
443 | |
444 | ret = pipe_buffer_setting(m66592, info: &info); |
445 | if (ret < 0) { |
446 | pr_err("pipe_buffer_setting fail\n" ); |
447 | return ret; |
448 | } |
449 | |
450 | (*counter)++; |
451 | if ((counter == &m66592->isochronous) && info.type == M66592_BULK) |
452 | m66592->bulk++; |
453 | |
454 | m66592_ep_setting(m66592, ep, desc, pipenum: info.pipe, dma); |
455 | pipe_initialize(ep); |
456 | |
457 | return 0; |
458 | } |
459 | |
460 | static int free_pipe_config(struct m66592_ep *ep) |
461 | { |
462 | struct m66592 *m66592 = ep->m66592; |
463 | struct m66592_pipe_info info; |
464 | |
465 | info.pipe = ep->pipenum; |
466 | info.type = ep->type; |
467 | pipe_buffer_release(m66592, info: &info); |
468 | m66592_ep_release(ep); |
469 | |
470 | return 0; |
471 | } |
472 | |
473 | /*-------------------------------------------------------------------------*/ |
474 | static void pipe_irq_enable(struct m66592 *m66592, u16 pipenum) |
475 | { |
476 | enable_irq_ready(m66592, pipenum); |
477 | enable_irq_nrdy(m66592, pipenum); |
478 | } |
479 | |
480 | static void pipe_irq_disable(struct m66592 *m66592, u16 pipenum) |
481 | { |
482 | disable_irq_ready(m66592, pipenum); |
483 | disable_irq_nrdy(m66592, pipenum); |
484 | } |
485 | |
486 | /* if complete is true, gadget driver complete function is not call */ |
487 | static void control_end(struct m66592 *m66592, unsigned ccpl) |
488 | { |
489 | m66592->ep[0].internal_ccpl = ccpl; |
490 | pipe_start(m66592, pipenum: 0); |
491 | m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR); |
492 | } |
493 | |
494 | static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req) |
495 | { |
496 | struct m66592 *m66592 = ep->m66592; |
497 | |
498 | pipe_change(m66592, pipenum: ep->pipenum); |
499 | m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0, |
500 | pat: (M66592_ISEL | M66592_CURPIPE), |
501 | M66592_CFIFOSEL); |
502 | m66592_write(m66592, M66592_BCLR, offset: ep->fifoctr); |
503 | if (req->req.length == 0) { |
504 | m66592_bset(m66592, M66592_BVAL, ep->fifoctr); |
505 | pipe_start(m66592, pipenum: 0); |
506 | transfer_complete(ep, req, status: 0); |
507 | } else { |
508 | m66592_write(m66592, val: ~M66592_BEMP0, M66592_BEMPSTS); |
509 | irq_ep0_write(ep, req); |
510 | } |
511 | } |
512 | |
513 | static void start_packet_write(struct m66592_ep *ep, struct m66592_request *req) |
514 | { |
515 | struct m66592 *m66592 = ep->m66592; |
516 | u16 tmp; |
517 | |
518 | pipe_change(m66592, pipenum: ep->pipenum); |
519 | disable_irq_empty(m66592, ep->pipenum); |
520 | pipe_start(m66592, pipenum: ep->pipenum); |
521 | |
522 | tmp = m66592_read(m66592, offset: ep->fifoctr); |
523 | if (unlikely((tmp & M66592_FRDY) == 0)) |
524 | pipe_irq_enable(m66592, pipenum: ep->pipenum); |
525 | else |
526 | irq_packet_write(ep, req); |
527 | } |
528 | |
529 | static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) |
530 | { |
531 | struct m66592 *m66592 = ep->m66592; |
532 | u16 pipenum = ep->pipenum; |
533 | |
534 | if (ep->pipenum == 0) { |
535 | m66592_mdfy(m66592, M66592_PIPE0, |
536 | pat: (M66592_ISEL | M66592_CURPIPE), |
537 | M66592_CFIFOSEL); |
538 | m66592_write(m66592, M66592_BCLR, offset: ep->fifoctr); |
539 | pipe_start(m66592, pipenum); |
540 | pipe_irq_enable(m66592, pipenum); |
541 | } else { |
542 | if (ep->use_dma) { |
543 | m66592_bset(m66592, M66592_TRCLR, ep->fifosel); |
544 | pipe_change(m66592, pipenum); |
545 | m66592_bset(m66592, M66592_TRENB, ep->fifosel); |
546 | m66592_write(m66592, |
547 | val: (req->req.length + ep->ep.maxpacket - 1) |
548 | / ep->ep.maxpacket, |
549 | offset: ep->fifotrn); |
550 | } |
551 | pipe_start(m66592, pipenum); /* trigger once */ |
552 | pipe_irq_enable(m66592, pipenum); |
553 | } |
554 | } |
555 | |
556 | static void start_packet(struct m66592_ep *ep, struct m66592_request *req) |
557 | { |
558 | if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) |
559 | start_packet_write(ep, req); |
560 | else |
561 | start_packet_read(ep, req); |
562 | } |
563 | |
564 | static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) |
565 | { |
566 | u16 ctsq; |
567 | |
568 | ctsq = m66592_read(m66592: ep->m66592, M66592_INTSTS0) & M66592_CTSQ; |
569 | |
570 | switch (ctsq) { |
571 | case M66592_CS_RDDS: |
572 | start_ep0_write(ep, req); |
573 | break; |
574 | case M66592_CS_WRDS: |
575 | start_packet_read(ep, req); |
576 | break; |
577 | |
578 | case M66592_CS_WRND: |
579 | control_end(m66592: ep->m66592, ccpl: 0); |
580 | break; |
581 | default: |
582 | pr_err("start_ep0: unexpect ctsq(%x)\n" , ctsq); |
583 | break; |
584 | } |
585 | } |
586 | |
587 | static void init_controller(struct m66592 *m66592) |
588 | { |
589 | unsigned int endian; |
590 | |
591 | if (m66592->pdata->on_chip) { |
592 | if (m66592->pdata->endian) |
593 | endian = 0; /* big endian */ |
594 | else |
595 | endian = M66592_LITTLE; /* little endian */ |
596 | |
597 | m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ |
598 | m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); |
599 | m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); |
600 | m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); |
601 | |
602 | /* This is a workaound for SH7722 2nd cut */ |
603 | m66592_bset(m66592, 0x8000, M66592_DVSTCTR); |
604 | m66592_bset(m66592, 0x1000, M66592_TESTMODE); |
605 | m66592_bclr(m66592, 0x8000, M66592_DVSTCTR); |
606 | |
607 | m66592_bset(m66592, M66592_INTL, M66592_INTENB1); |
608 | |
609 | m66592_write(m66592, val: 0, M66592_CFBCFG); |
610 | m66592_write(m66592, val: 0, M66592_D0FBCFG); |
611 | m66592_bset(m66592, endian, M66592_CFBCFG); |
612 | m66592_bset(m66592, endian, M66592_D0FBCFG); |
613 | } else { |
614 | unsigned int clock, vif, irq_sense; |
615 | |
616 | if (m66592->pdata->endian) |
617 | endian = M66592_BIGEND; /* big endian */ |
618 | else |
619 | endian = 0; /* little endian */ |
620 | |
621 | if (m66592->pdata->vif) |
622 | vif = M66592_LDRV; /* 3.3v */ |
623 | else |
624 | vif = 0; /* 1.5v */ |
625 | |
626 | switch (m66592->pdata->xtal) { |
627 | case M66592_PLATDATA_XTAL_12MHZ: |
628 | clock = M66592_XTAL12; |
629 | break; |
630 | case M66592_PLATDATA_XTAL_24MHZ: |
631 | clock = M66592_XTAL24; |
632 | break; |
633 | case M66592_PLATDATA_XTAL_48MHZ: |
634 | clock = M66592_XTAL48; |
635 | break; |
636 | default: |
637 | pr_warn("m66592-udc: xtal configuration error\n" ); |
638 | clock = 0; |
639 | } |
640 | |
641 | switch (m66592->irq_trigger) { |
642 | case IRQF_TRIGGER_LOW: |
643 | irq_sense = M66592_INTL; |
644 | break; |
645 | case IRQF_TRIGGER_FALLING: |
646 | irq_sense = 0; |
647 | break; |
648 | default: |
649 | pr_warn("m66592-udc: irq trigger config error\n" ); |
650 | irq_sense = 0; |
651 | } |
652 | |
653 | m66592_bset(m66592, |
654 | (vif & M66592_LDRV) | (endian & M66592_BIGEND), |
655 | M66592_PINCFG); |
656 | m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ |
657 | m66592_mdfy(m66592, val: clock & M66592_XTAL, M66592_XTAL, |
658 | M66592_SYSCFG); |
659 | m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); |
660 | m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); |
661 | m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); |
662 | |
663 | m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); |
664 | |
665 | msleep(msecs: 3); |
666 | |
667 | m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); |
668 | |
669 | msleep(msecs: 1); |
670 | |
671 | m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); |
672 | |
673 | m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); |
674 | m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, |
675 | M66592_DMA0CFG); |
676 | } |
677 | } |
678 | |
679 | static void disable_controller(struct m66592 *m66592) |
680 | { |
681 | m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE); |
682 | if (!m66592->pdata->on_chip) { |
683 | m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); |
684 | udelay(1); |
685 | m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); |
686 | udelay(1); |
687 | m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); |
688 | udelay(1); |
689 | m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); |
690 | } |
691 | } |
692 | |
693 | static void m66592_start_xclock(struct m66592 *m66592) |
694 | { |
695 | u16 tmp; |
696 | |
697 | if (!m66592->pdata->on_chip) { |
698 | tmp = m66592_read(m66592, M66592_SYSCFG); |
699 | if (!(tmp & M66592_XCKE)) |
700 | m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); |
701 | } |
702 | } |
703 | |
704 | /*-------------------------------------------------------------------------*/ |
705 | static void transfer_complete(struct m66592_ep *ep, |
706 | struct m66592_request *req, int status) |
707 | __releases(m66592->lock) |
708 | __acquires(m66592->lock) |
709 | { |
710 | int restart = 0; |
711 | |
712 | if (unlikely(ep->pipenum == 0)) { |
713 | if (ep->internal_ccpl) { |
714 | ep->internal_ccpl = 0; |
715 | return; |
716 | } |
717 | } |
718 | |
719 | list_del_init(entry: &req->queue); |
720 | if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) |
721 | req->req.status = -ESHUTDOWN; |
722 | else |
723 | req->req.status = status; |
724 | |
725 | if (!list_empty(head: &ep->queue)) |
726 | restart = 1; |
727 | |
728 | spin_unlock(lock: &ep->m66592->lock); |
729 | usb_gadget_giveback_request(ep: &ep->ep, req: &req->req); |
730 | spin_lock(lock: &ep->m66592->lock); |
731 | |
732 | if (restart) { |
733 | req = list_entry(ep->queue.next, struct m66592_request, queue); |
734 | if (ep->ep.desc) |
735 | start_packet(ep, req); |
736 | } |
737 | } |
738 | |
739 | static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) |
740 | { |
741 | int i; |
742 | u16 tmp; |
743 | unsigned bufsize; |
744 | size_t size; |
745 | void *buf; |
746 | u16 pipenum = ep->pipenum; |
747 | struct m66592 *m66592 = ep->m66592; |
748 | |
749 | pipe_change(m66592, pipenum); |
750 | m66592_bset(m66592, M66592_ISEL, ep->fifosel); |
751 | |
752 | i = 0; |
753 | do { |
754 | tmp = m66592_read(m66592, offset: ep->fifoctr); |
755 | if (i++ > 100000) { |
756 | pr_err("pipe0 is busy. maybe cpu i/o bus " |
757 | "conflict. please power off this controller." ); |
758 | return; |
759 | } |
760 | ndelay(1); |
761 | } while ((tmp & M66592_FRDY) == 0); |
762 | |
763 | /* prepare parameters */ |
764 | bufsize = get_buffer_size(m66592, pipenum); |
765 | buf = req->req.buf + req->req.actual; |
766 | size = min(bufsize, req->req.length - req->req.actual); |
767 | |
768 | /* write fifo */ |
769 | if (req->req.buf) { |
770 | if (size > 0) |
771 | m66592_write_fifo(m66592, ep, buf, len: size); |
772 | if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) |
773 | m66592_bset(m66592, M66592_BVAL, ep->fifoctr); |
774 | } |
775 | |
776 | /* update parameters */ |
777 | req->req.actual += size; |
778 | |
779 | /* check transfer finish */ |
780 | if ((!req->req.zero && (req->req.actual == req->req.length)) |
781 | || (size % ep->ep.maxpacket) |
782 | || (size == 0)) { |
783 | disable_irq_ready(m66592, pipenum); |
784 | disable_irq_empty(m66592, pipenum); |
785 | } else { |
786 | disable_irq_ready(m66592, pipenum); |
787 | enable_irq_empty(m66592, pipenum); |
788 | } |
789 | pipe_start(m66592, pipenum); |
790 | } |
791 | |
792 | static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) |
793 | { |
794 | u16 tmp; |
795 | unsigned bufsize; |
796 | size_t size; |
797 | void *buf; |
798 | u16 pipenum = ep->pipenum; |
799 | struct m66592 *m66592 = ep->m66592; |
800 | |
801 | pipe_change(m66592, pipenum); |
802 | tmp = m66592_read(m66592, offset: ep->fifoctr); |
803 | if (unlikely((tmp & M66592_FRDY) == 0)) { |
804 | pipe_stop(m66592, pipenum); |
805 | pipe_irq_disable(m66592, pipenum); |
806 | pr_err("write fifo not ready. pipnum=%d\n" , pipenum); |
807 | return; |
808 | } |
809 | |
810 | /* prepare parameters */ |
811 | bufsize = get_buffer_size(m66592, pipenum); |
812 | buf = req->req.buf + req->req.actual; |
813 | size = min(bufsize, req->req.length - req->req.actual); |
814 | |
815 | /* write fifo */ |
816 | if (req->req.buf) { |
817 | m66592_write_fifo(m66592, ep, buf, len: size); |
818 | if ((size == 0) |
819 | || ((size % ep->ep.maxpacket) != 0) |
820 | || ((bufsize != ep->ep.maxpacket) |
821 | && (bufsize > size))) |
822 | m66592_bset(m66592, M66592_BVAL, ep->fifoctr); |
823 | } |
824 | |
825 | /* update parameters */ |
826 | req->req.actual += size; |
827 | /* check transfer finish */ |
828 | if ((!req->req.zero && (req->req.actual == req->req.length)) |
829 | || (size % ep->ep.maxpacket) |
830 | || (size == 0)) { |
831 | disable_irq_ready(m66592, pipenum); |
832 | enable_irq_empty(m66592, pipenum); |
833 | } else { |
834 | disable_irq_empty(m66592, pipenum); |
835 | pipe_irq_enable(m66592, pipenum); |
836 | } |
837 | } |
838 | |
839 | static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) |
840 | { |
841 | u16 tmp; |
842 | int rcv_len, bufsize, req_len; |
843 | int size; |
844 | void *buf; |
845 | u16 pipenum = ep->pipenum; |
846 | struct m66592 *m66592 = ep->m66592; |
847 | int finish = 0; |
848 | |
849 | pipe_change(m66592, pipenum); |
850 | tmp = m66592_read(m66592, offset: ep->fifoctr); |
851 | if (unlikely((tmp & M66592_FRDY) == 0)) { |
852 | req->req.status = -EPIPE; |
853 | pipe_stop(m66592, pipenum); |
854 | pipe_irq_disable(m66592, pipenum); |
855 | pr_err("read fifo not ready" ); |
856 | return; |
857 | } |
858 | |
859 | /* prepare parameters */ |
860 | rcv_len = tmp & M66592_DTLN; |
861 | bufsize = get_buffer_size(m66592, pipenum); |
862 | |
863 | buf = req->req.buf + req->req.actual; |
864 | req_len = req->req.length - req->req.actual; |
865 | if (rcv_len < bufsize) |
866 | size = min(rcv_len, req_len); |
867 | else |
868 | size = min(bufsize, req_len); |
869 | |
870 | /* update parameters */ |
871 | req->req.actual += size; |
872 | |
873 | /* check transfer finish */ |
874 | if ((!req->req.zero && (req->req.actual == req->req.length)) |
875 | || (size % ep->ep.maxpacket) |
876 | || (size == 0)) { |
877 | pipe_stop(m66592, pipenum); |
878 | pipe_irq_disable(m66592, pipenum); |
879 | finish = 1; |
880 | } |
881 | |
882 | /* read fifo */ |
883 | if (req->req.buf) { |
884 | if (size == 0) |
885 | m66592_write(m66592, M66592_BCLR, offset: ep->fifoctr); |
886 | else |
887 | m66592_read_fifo(m66592, offset: ep->fifoaddr, buf, len: size); |
888 | } |
889 | |
890 | if ((ep->pipenum != 0) && finish) |
891 | transfer_complete(ep, req, status: 0); |
892 | } |
893 | |
894 | static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) |
895 | { |
896 | u16 check; |
897 | u16 pipenum; |
898 | struct m66592_ep *ep; |
899 | struct m66592_request *req; |
900 | |
901 | if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { |
902 | m66592_write(m66592, val: ~M66592_BRDY0, M66592_BRDYSTS); |
903 | m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, |
904 | M66592_CFIFOSEL); |
905 | |
906 | ep = &m66592->ep[0]; |
907 | req = list_entry(ep->queue.next, struct m66592_request, queue); |
908 | irq_packet_read(ep, req); |
909 | } else { |
910 | for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { |
911 | check = 1 << pipenum; |
912 | if ((status & check) && (enb & check)) { |
913 | m66592_write(m66592, val: ~check, M66592_BRDYSTS); |
914 | ep = m66592->pipenum2ep[pipenum]; |
915 | req = list_entry(ep->queue.next, |
916 | struct m66592_request, queue); |
917 | if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) |
918 | irq_packet_write(ep, req); |
919 | else |
920 | irq_packet_read(ep, req); |
921 | } |
922 | } |
923 | } |
924 | } |
925 | |
926 | static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb) |
927 | { |
928 | u16 tmp; |
929 | u16 check; |
930 | u16 pipenum; |
931 | struct m66592_ep *ep; |
932 | struct m66592_request *req; |
933 | |
934 | if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) { |
935 | m66592_write(m66592, val: ~M66592_BEMP0, M66592_BEMPSTS); |
936 | |
937 | ep = &m66592->ep[0]; |
938 | req = list_entry(ep->queue.next, struct m66592_request, queue); |
939 | irq_ep0_write(ep, req); |
940 | } else { |
941 | for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { |
942 | check = 1 << pipenum; |
943 | if ((status & check) && (enb & check)) { |
944 | m66592_write(m66592, val: ~check, M66592_BEMPSTS); |
945 | tmp = control_reg_get(m66592, pipenum); |
946 | if ((tmp & M66592_INBUFM) == 0) { |
947 | disable_irq_empty(m66592, pipenum); |
948 | pipe_irq_disable(m66592, pipenum); |
949 | pipe_stop(m66592, pipenum); |
950 | ep = m66592->pipenum2ep[pipenum]; |
951 | req = list_entry(ep->queue.next, |
952 | struct m66592_request, |
953 | queue); |
954 | if (!list_empty(head: &ep->queue)) |
955 | transfer_complete(ep, req, status: 0); |
956 | } |
957 | } |
958 | } |
959 | } |
960 | } |
961 | |
962 | static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) |
963 | __releases(m66592->lock) |
964 | __acquires(m66592->lock) |
965 | { |
966 | struct m66592_ep *ep; |
967 | u16 pid; |
968 | u16 status = 0; |
969 | u16 w_index = le16_to_cpu(ctrl->wIndex); |
970 | |
971 | switch (ctrl->bRequestType & USB_RECIP_MASK) { |
972 | case USB_RECIP_DEVICE: |
973 | status = 1 << USB_DEVICE_SELF_POWERED; |
974 | break; |
975 | case USB_RECIP_INTERFACE: |
976 | status = 0; |
977 | break; |
978 | case USB_RECIP_ENDPOINT: |
979 | ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; |
980 | pid = control_reg_get_pid(m66592, pipenum: ep->pipenum); |
981 | if (pid == M66592_PID_STALL) |
982 | status = 1 << USB_ENDPOINT_HALT; |
983 | else |
984 | status = 0; |
985 | break; |
986 | default: |
987 | pipe_stall(m66592, pipenum: 0); |
988 | return; /* exit */ |
989 | } |
990 | |
991 | m66592->ep0_data = cpu_to_le16(status); |
992 | m66592->ep0_req->buf = &m66592->ep0_data; |
993 | m66592->ep0_req->length = 2; |
994 | /* AV: what happens if we get called again before that gets through? */ |
995 | spin_unlock(lock: &m66592->lock); |
996 | m66592_queue(ep: m66592->gadget.ep0, req: m66592->ep0_req, GFP_KERNEL); |
997 | spin_lock(lock: &m66592->lock); |
998 | } |
999 | |
1000 | static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) |
1001 | { |
1002 | switch (ctrl->bRequestType & USB_RECIP_MASK) { |
1003 | case USB_RECIP_DEVICE: |
1004 | control_end(m66592, ccpl: 1); |
1005 | break; |
1006 | case USB_RECIP_INTERFACE: |
1007 | control_end(m66592, ccpl: 1); |
1008 | break; |
1009 | case USB_RECIP_ENDPOINT: { |
1010 | struct m66592_ep *ep; |
1011 | struct m66592_request *req; |
1012 | u16 w_index = le16_to_cpu(ctrl->wIndex); |
1013 | |
1014 | ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; |
1015 | pipe_stop(m66592, pipenum: ep->pipenum); |
1016 | control_reg_sqclr(m66592, pipenum: ep->pipenum); |
1017 | |
1018 | control_end(m66592, ccpl: 1); |
1019 | |
1020 | req = list_entry(ep->queue.next, |
1021 | struct m66592_request, queue); |
1022 | if (ep->busy) { |
1023 | ep->busy = 0; |
1024 | if (list_empty(head: &ep->queue)) |
1025 | break; |
1026 | start_packet(ep, req); |
1027 | } else if (!list_empty(head: &ep->queue)) |
1028 | pipe_start(m66592, pipenum: ep->pipenum); |
1029 | } |
1030 | break; |
1031 | default: |
1032 | pipe_stall(m66592, pipenum: 0); |
1033 | break; |
1034 | } |
1035 | } |
1036 | |
1037 | static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) |
1038 | { |
1039 | u16 tmp; |
1040 | int timeout = 3000; |
1041 | |
1042 | switch (ctrl->bRequestType & USB_RECIP_MASK) { |
1043 | case USB_RECIP_DEVICE: |
1044 | switch (le16_to_cpu(ctrl->wValue)) { |
1045 | case USB_DEVICE_TEST_MODE: |
1046 | control_end(m66592, ccpl: 1); |
1047 | /* Wait for the completion of status stage */ |
1048 | do { |
1049 | tmp = m66592_read(m66592, M66592_INTSTS0) & |
1050 | M66592_CTSQ; |
1051 | udelay(1); |
1052 | } while (tmp != M66592_CS_IDST && timeout-- > 0); |
1053 | |
1054 | if (tmp == M66592_CS_IDST) |
1055 | m66592_bset(m66592, |
1056 | le16_to_cpu(ctrl->wIndex >> 8), |
1057 | M66592_TESTMODE); |
1058 | break; |
1059 | default: |
1060 | pipe_stall(m66592, pipenum: 0); |
1061 | break; |
1062 | } |
1063 | break; |
1064 | case USB_RECIP_INTERFACE: |
1065 | control_end(m66592, ccpl: 1); |
1066 | break; |
1067 | case USB_RECIP_ENDPOINT: { |
1068 | struct m66592_ep *ep; |
1069 | u16 w_index = le16_to_cpu(ctrl->wIndex); |
1070 | |
1071 | ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; |
1072 | pipe_stall(m66592, pipenum: ep->pipenum); |
1073 | |
1074 | control_end(m66592, ccpl: 1); |
1075 | } |
1076 | break; |
1077 | default: |
1078 | pipe_stall(m66592, pipenum: 0); |
1079 | break; |
1080 | } |
1081 | } |
1082 | |
1083 | /* if return value is true, call class driver's setup() */ |
1084 | static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) |
1085 | { |
1086 | u16 *p = (u16 *)ctrl; |
1087 | unsigned long offset = M66592_USBREQ; |
1088 | int i, ret = 0; |
1089 | |
1090 | /* read fifo */ |
1091 | m66592_write(m66592, val: ~M66592_VALID, M66592_INTSTS0); |
1092 | |
1093 | for (i = 0; i < 4; i++) |
1094 | p[i] = m66592_read(m66592, offset: offset + i*2); |
1095 | |
1096 | /* check request */ |
1097 | if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { |
1098 | switch (ctrl->bRequest) { |
1099 | case USB_REQ_GET_STATUS: |
1100 | get_status(m66592, ctrl); |
1101 | break; |
1102 | case USB_REQ_CLEAR_FEATURE: |
1103 | clear_feature(m66592, ctrl); |
1104 | break; |
1105 | case USB_REQ_SET_FEATURE: |
1106 | set_feature(m66592, ctrl); |
1107 | break; |
1108 | default: |
1109 | ret = 1; |
1110 | break; |
1111 | } |
1112 | } else |
1113 | ret = 1; |
1114 | return ret; |
1115 | } |
1116 | |
1117 | static void m66592_update_usb_speed(struct m66592 *m66592) |
1118 | { |
1119 | u16 speed = get_usb_speed(m66592); |
1120 | |
1121 | switch (speed) { |
1122 | case M66592_HSMODE: |
1123 | m66592->gadget.speed = USB_SPEED_HIGH; |
1124 | break; |
1125 | case M66592_FSMODE: |
1126 | m66592->gadget.speed = USB_SPEED_FULL; |
1127 | break; |
1128 | default: |
1129 | m66592->gadget.speed = USB_SPEED_UNKNOWN; |
1130 | pr_err("USB speed unknown\n" ); |
1131 | } |
1132 | } |
1133 | |
1134 | static void irq_device_state(struct m66592 *m66592) |
1135 | { |
1136 | u16 dvsq; |
1137 | |
1138 | dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ; |
1139 | m66592_write(m66592, val: ~M66592_DVST, M66592_INTSTS0); |
1140 | |
1141 | if (dvsq == M66592_DS_DFLT) { /* bus reset */ |
1142 | usb_gadget_udc_reset(gadget: &m66592->gadget, driver: m66592->driver); |
1143 | m66592_update_usb_speed(m66592); |
1144 | } |
1145 | if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) |
1146 | m66592_update_usb_speed(m66592); |
1147 | if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) |
1148 | && m66592->gadget.speed == USB_SPEED_UNKNOWN) |
1149 | m66592_update_usb_speed(m66592); |
1150 | |
1151 | m66592->old_dvsq = dvsq; |
1152 | } |
1153 | |
1154 | static void irq_control_stage(struct m66592 *m66592) |
1155 | __releases(m66592->lock) |
1156 | __acquires(m66592->lock) |
1157 | { |
1158 | struct usb_ctrlrequest ctrl; |
1159 | u16 ctsq; |
1160 | |
1161 | ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ; |
1162 | m66592_write(m66592, val: ~M66592_CTRT, M66592_INTSTS0); |
1163 | |
1164 | switch (ctsq) { |
1165 | case M66592_CS_IDST: { |
1166 | struct m66592_ep *ep; |
1167 | struct m66592_request *req; |
1168 | ep = &m66592->ep[0]; |
1169 | req = list_entry(ep->queue.next, struct m66592_request, queue); |
1170 | transfer_complete(ep, req, status: 0); |
1171 | } |
1172 | break; |
1173 | |
1174 | case M66592_CS_RDDS: |
1175 | case M66592_CS_WRDS: |
1176 | case M66592_CS_WRND: |
1177 | if (setup_packet(m66592, ctrl: &ctrl)) { |
1178 | spin_unlock(lock: &m66592->lock); |
1179 | if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0) |
1180 | pipe_stall(m66592, pipenum: 0); |
1181 | spin_lock(lock: &m66592->lock); |
1182 | } |
1183 | break; |
1184 | case M66592_CS_RDSS: |
1185 | case M66592_CS_WRSS: |
1186 | control_end(m66592, ccpl: 0); |
1187 | break; |
1188 | default: |
1189 | pr_err("ctrl_stage: unexpect ctsq(%x)\n" , ctsq); |
1190 | break; |
1191 | } |
1192 | } |
1193 | |
1194 | static irqreturn_t m66592_irq(int irq, void *_m66592) |
1195 | { |
1196 | struct m66592 *m66592 = _m66592; |
1197 | u16 intsts0; |
1198 | u16 intenb0; |
1199 | u16 savepipe; |
1200 | u16 mask0; |
1201 | |
1202 | spin_lock(lock: &m66592->lock); |
1203 | |
1204 | intsts0 = m66592_read(m66592, M66592_INTSTS0); |
1205 | intenb0 = m66592_read(m66592, M66592_INTENB0); |
1206 | |
1207 | if (m66592->pdata->on_chip && !intsts0 && !intenb0) { |
1208 | /* |
1209 | * When USB clock stops, it cannot read register. Even if a |
1210 | * clock stops, the interrupt occurs. So this driver turn on |
1211 | * a clock by this timing and do re-reading of register. |
1212 | */ |
1213 | m66592_start_xclock(m66592); |
1214 | intsts0 = m66592_read(m66592, M66592_INTSTS0); |
1215 | intenb0 = m66592_read(m66592, M66592_INTENB0); |
1216 | } |
1217 | |
1218 | savepipe = m66592_read(m66592, M66592_CFIFOSEL); |
1219 | |
1220 | mask0 = intsts0 & intenb0; |
1221 | if (mask0) { |
1222 | u16 brdysts = m66592_read(m66592, M66592_BRDYSTS); |
1223 | u16 bempsts = m66592_read(m66592, M66592_BEMPSTS); |
1224 | u16 brdyenb = m66592_read(m66592, M66592_BRDYENB); |
1225 | u16 bempenb = m66592_read(m66592, M66592_BEMPENB); |
1226 | |
1227 | if (mask0 & M66592_VBINT) { |
1228 | m66592_write(m66592, val: 0xffff & ~M66592_VBINT, |
1229 | M66592_INTSTS0); |
1230 | m66592_start_xclock(m66592); |
1231 | |
1232 | /* start vbus sampling */ |
1233 | m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) |
1234 | & M66592_VBSTS; |
1235 | m66592->scount = M66592_MAX_SAMPLING; |
1236 | |
1237 | mod_timer(timer: &m66592->timer, |
1238 | expires: jiffies + msecs_to_jiffies(m: 50)); |
1239 | } |
1240 | if (intsts0 & M66592_DVSQ) |
1241 | irq_device_state(m66592); |
1242 | |
1243 | if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) |
1244 | && (brdysts & brdyenb)) { |
1245 | irq_pipe_ready(m66592, status: brdysts, enb: brdyenb); |
1246 | } |
1247 | if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) |
1248 | && (bempsts & bempenb)) { |
1249 | irq_pipe_empty(m66592, status: bempsts, enb: bempenb); |
1250 | } |
1251 | |
1252 | if (intsts0 & M66592_CTRT) |
1253 | irq_control_stage(m66592); |
1254 | } |
1255 | |
1256 | m66592_write(m66592, val: savepipe, M66592_CFIFOSEL); |
1257 | |
1258 | spin_unlock(lock: &m66592->lock); |
1259 | return IRQ_HANDLED; |
1260 | } |
1261 | |
1262 | static void m66592_timer(struct timer_list *t) |
1263 | { |
1264 | struct m66592 *m66592 = from_timer(m66592, t, timer); |
1265 | unsigned long flags; |
1266 | u16 tmp; |
1267 | |
1268 | spin_lock_irqsave(&m66592->lock, flags); |
1269 | tmp = m66592_read(m66592, M66592_SYSCFG); |
1270 | if (!(tmp & M66592_RCKE)) { |
1271 | m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); |
1272 | udelay(10); |
1273 | m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); |
1274 | } |
1275 | if (m66592->scount > 0) { |
1276 | tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS; |
1277 | if (tmp == m66592->old_vbus) { |
1278 | m66592->scount--; |
1279 | if (m66592->scount == 0) { |
1280 | if (tmp == M66592_VBSTS) |
1281 | m66592_usb_connect(m66592); |
1282 | else |
1283 | m66592_usb_disconnect(m66592); |
1284 | } else { |
1285 | mod_timer(timer: &m66592->timer, |
1286 | expires: jiffies + msecs_to_jiffies(m: 50)); |
1287 | } |
1288 | } else { |
1289 | m66592->scount = M66592_MAX_SAMPLING; |
1290 | m66592->old_vbus = tmp; |
1291 | mod_timer(timer: &m66592->timer, |
1292 | expires: jiffies + msecs_to_jiffies(m: 50)); |
1293 | } |
1294 | } |
1295 | spin_unlock_irqrestore(lock: &m66592->lock, flags); |
1296 | } |
1297 | |
1298 | /*-------------------------------------------------------------------------*/ |
1299 | static int m66592_enable(struct usb_ep *_ep, |
1300 | const struct usb_endpoint_descriptor *desc) |
1301 | { |
1302 | struct m66592_ep *ep; |
1303 | |
1304 | ep = container_of(_ep, struct m66592_ep, ep); |
1305 | return alloc_pipe_config(ep, desc); |
1306 | } |
1307 | |
1308 | static int m66592_disable(struct usb_ep *_ep) |
1309 | { |
1310 | struct m66592_ep *ep; |
1311 | struct m66592_request *req; |
1312 | unsigned long flags; |
1313 | |
1314 | ep = container_of(_ep, struct m66592_ep, ep); |
1315 | BUG_ON(!ep); |
1316 | |
1317 | while (!list_empty(head: &ep->queue)) { |
1318 | req = list_entry(ep->queue.next, struct m66592_request, queue); |
1319 | spin_lock_irqsave(&ep->m66592->lock, flags); |
1320 | transfer_complete(ep, req, status: -ECONNRESET); |
1321 | spin_unlock_irqrestore(lock: &ep->m66592->lock, flags); |
1322 | } |
1323 | |
1324 | pipe_irq_disable(m66592: ep->m66592, pipenum: ep->pipenum); |
1325 | return free_pipe_config(ep); |
1326 | } |
1327 | |
1328 | static struct usb_request *m66592_alloc_request(struct usb_ep *_ep, |
1329 | gfp_t gfp_flags) |
1330 | { |
1331 | struct m66592_request *req; |
1332 | |
1333 | req = kzalloc(size: sizeof(struct m66592_request), flags: gfp_flags); |
1334 | if (!req) |
1335 | return NULL; |
1336 | |
1337 | INIT_LIST_HEAD(list: &req->queue); |
1338 | |
1339 | return &req->req; |
1340 | } |
1341 | |
1342 | static void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req) |
1343 | { |
1344 | struct m66592_request *req; |
1345 | |
1346 | req = container_of(_req, struct m66592_request, req); |
1347 | kfree(objp: req); |
1348 | } |
1349 | |
1350 | static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, |
1351 | gfp_t gfp_flags) |
1352 | { |
1353 | struct m66592_ep *ep; |
1354 | struct m66592_request *req; |
1355 | unsigned long flags; |
1356 | int request = 0; |
1357 | |
1358 | ep = container_of(_ep, struct m66592_ep, ep); |
1359 | req = container_of(_req, struct m66592_request, req); |
1360 | |
1361 | if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) |
1362 | return -ESHUTDOWN; |
1363 | |
1364 | spin_lock_irqsave(&ep->m66592->lock, flags); |
1365 | |
1366 | if (list_empty(head: &ep->queue)) |
1367 | request = 1; |
1368 | |
1369 | list_add_tail(new: &req->queue, head: &ep->queue); |
1370 | req->req.actual = 0; |
1371 | req->req.status = -EINPROGRESS; |
1372 | |
1373 | if (ep->ep.desc == NULL) /* control */ |
1374 | start_ep0(ep, req); |
1375 | else { |
1376 | if (request && !ep->busy) |
1377 | start_packet(ep, req); |
1378 | } |
1379 | |
1380 | spin_unlock_irqrestore(lock: &ep->m66592->lock, flags); |
1381 | |
1382 | return 0; |
1383 | } |
1384 | |
1385 | static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req) |
1386 | { |
1387 | struct m66592_ep *ep; |
1388 | struct m66592_request *req; |
1389 | unsigned long flags; |
1390 | |
1391 | ep = container_of(_ep, struct m66592_ep, ep); |
1392 | req = container_of(_req, struct m66592_request, req); |
1393 | |
1394 | spin_lock_irqsave(&ep->m66592->lock, flags); |
1395 | if (!list_empty(head: &ep->queue)) |
1396 | transfer_complete(ep, req, status: -ECONNRESET); |
1397 | spin_unlock_irqrestore(lock: &ep->m66592->lock, flags); |
1398 | |
1399 | return 0; |
1400 | } |
1401 | |
1402 | static int m66592_set_halt(struct usb_ep *_ep, int value) |
1403 | { |
1404 | struct m66592_ep *ep = container_of(_ep, struct m66592_ep, ep); |
1405 | unsigned long flags; |
1406 | int ret = 0; |
1407 | |
1408 | spin_lock_irqsave(&ep->m66592->lock, flags); |
1409 | if (!list_empty(head: &ep->queue)) { |
1410 | ret = -EAGAIN; |
1411 | } else if (value) { |
1412 | ep->busy = 1; |
1413 | pipe_stall(m66592: ep->m66592, pipenum: ep->pipenum); |
1414 | } else { |
1415 | ep->busy = 0; |
1416 | pipe_stop(m66592: ep->m66592, pipenum: ep->pipenum); |
1417 | } |
1418 | spin_unlock_irqrestore(lock: &ep->m66592->lock, flags); |
1419 | return ret; |
1420 | } |
1421 | |
1422 | static void m66592_fifo_flush(struct usb_ep *_ep) |
1423 | { |
1424 | struct m66592_ep *ep; |
1425 | unsigned long flags; |
1426 | |
1427 | ep = container_of(_ep, struct m66592_ep, ep); |
1428 | spin_lock_irqsave(&ep->m66592->lock, flags); |
1429 | if (list_empty(head: &ep->queue) && !ep->busy) { |
1430 | pipe_stop(m66592: ep->m66592, pipenum: ep->pipenum); |
1431 | m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr); |
1432 | } |
1433 | spin_unlock_irqrestore(lock: &ep->m66592->lock, flags); |
1434 | } |
1435 | |
1436 | static const struct usb_ep_ops m66592_ep_ops = { |
1437 | .enable = m66592_enable, |
1438 | .disable = m66592_disable, |
1439 | |
1440 | .alloc_request = m66592_alloc_request, |
1441 | .free_request = m66592_free_request, |
1442 | |
1443 | .queue = m66592_queue, |
1444 | .dequeue = m66592_dequeue, |
1445 | |
1446 | .set_halt = m66592_set_halt, |
1447 | .fifo_flush = m66592_fifo_flush, |
1448 | }; |
1449 | |
1450 | /*-------------------------------------------------------------------------*/ |
1451 | static int m66592_udc_start(struct usb_gadget *g, |
1452 | struct usb_gadget_driver *driver) |
1453 | { |
1454 | struct m66592 *m66592 = to_m66592(g); |
1455 | |
1456 | /* hook up the driver */ |
1457 | m66592->driver = driver; |
1458 | |
1459 | m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); |
1460 | if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { |
1461 | m66592_start_xclock(m66592); |
1462 | /* start vbus sampling */ |
1463 | m66592->old_vbus = m66592_read(m66592, |
1464 | M66592_INTSTS0) & M66592_VBSTS; |
1465 | m66592->scount = M66592_MAX_SAMPLING; |
1466 | mod_timer(timer: &m66592->timer, expires: jiffies + msecs_to_jiffies(m: 50)); |
1467 | } |
1468 | |
1469 | return 0; |
1470 | } |
1471 | |
1472 | static int m66592_udc_stop(struct usb_gadget *g) |
1473 | { |
1474 | struct m66592 *m66592 = to_m66592(g); |
1475 | |
1476 | m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); |
1477 | |
1478 | init_controller(m66592); |
1479 | disable_controller(m66592); |
1480 | |
1481 | m66592->driver = NULL; |
1482 | |
1483 | return 0; |
1484 | } |
1485 | |
1486 | /*-------------------------------------------------------------------------*/ |
1487 | static int m66592_get_frame(struct usb_gadget *_gadget) |
1488 | { |
1489 | struct m66592 *m66592 = gadget_to_m66592(_gadget); |
1490 | return m66592_read(m66592, M66592_FRMNUM) & 0x03FF; |
1491 | } |
1492 | |
1493 | static int m66592_pullup(struct usb_gadget *gadget, int is_on) |
1494 | { |
1495 | struct m66592 *m66592 = gadget_to_m66592(gadget); |
1496 | unsigned long flags; |
1497 | |
1498 | spin_lock_irqsave(&m66592->lock, flags); |
1499 | if (is_on) |
1500 | m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); |
1501 | else |
1502 | m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); |
1503 | spin_unlock_irqrestore(lock: &m66592->lock, flags); |
1504 | |
1505 | return 0; |
1506 | } |
1507 | |
1508 | static const struct usb_gadget_ops m66592_gadget_ops = { |
1509 | .get_frame = m66592_get_frame, |
1510 | .udc_start = m66592_udc_start, |
1511 | .udc_stop = m66592_udc_stop, |
1512 | .pullup = m66592_pullup, |
1513 | }; |
1514 | |
1515 | static void m66592_remove(struct platform_device *pdev) |
1516 | { |
1517 | struct m66592 *m66592 = platform_get_drvdata(pdev); |
1518 | |
1519 | usb_del_gadget_udc(gadget: &m66592->gadget); |
1520 | |
1521 | timer_shutdown_sync(timer: &m66592->timer); |
1522 | iounmap(addr: m66592->reg); |
1523 | free_irq(platform_get_irq(pdev, 0), m66592); |
1524 | m66592_free_request(ep: &m66592->ep[0].ep, req: m66592->ep0_req); |
1525 | if (m66592->pdata->on_chip) { |
1526 | clk_disable(clk: m66592->clk); |
1527 | clk_put(clk: m66592->clk); |
1528 | } |
1529 | kfree(objp: m66592); |
1530 | } |
1531 | |
1532 | static void nop_completion(struct usb_ep *ep, struct usb_request *r) |
1533 | { |
1534 | } |
1535 | |
1536 | static int m66592_probe(struct platform_device *pdev) |
1537 | { |
1538 | struct resource *res, *ires; |
1539 | void __iomem *reg = NULL; |
1540 | struct m66592 *m66592 = NULL; |
1541 | char clk_name[8]; |
1542 | int ret = 0; |
1543 | int i; |
1544 | |
1545 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1546 | if (!res) { |
1547 | ret = -ENODEV; |
1548 | pr_err("platform_get_resource error.\n" ); |
1549 | goto clean_up; |
1550 | } |
1551 | |
1552 | ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1553 | if (!ires) { |
1554 | ret = -ENODEV; |
1555 | dev_err(&pdev->dev, |
1556 | "platform_get_resource IORESOURCE_IRQ error.\n" ); |
1557 | goto clean_up; |
1558 | } |
1559 | |
1560 | reg = ioremap(offset: res->start, size: resource_size(res)); |
1561 | if (reg == NULL) { |
1562 | ret = -ENOMEM; |
1563 | pr_err("ioremap error.\n" ); |
1564 | goto clean_up; |
1565 | } |
1566 | |
1567 | if (dev_get_platdata(dev: &pdev->dev) == NULL) { |
1568 | dev_err(&pdev->dev, "no platform data\n" ); |
1569 | ret = -ENODEV; |
1570 | goto clean_up; |
1571 | } |
1572 | |
1573 | /* initialize ucd */ |
1574 | m66592 = kzalloc(size: sizeof(struct m66592), GFP_KERNEL); |
1575 | if (m66592 == NULL) { |
1576 | ret = -ENOMEM; |
1577 | goto clean_up; |
1578 | } |
1579 | |
1580 | m66592->pdata = dev_get_platdata(dev: &pdev->dev); |
1581 | m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK; |
1582 | |
1583 | spin_lock_init(&m66592->lock); |
1584 | platform_set_drvdata(pdev, data: m66592); |
1585 | |
1586 | m66592->gadget.ops = &m66592_gadget_ops; |
1587 | m66592->gadget.max_speed = USB_SPEED_HIGH; |
1588 | m66592->gadget.name = udc_name; |
1589 | |
1590 | timer_setup(&m66592->timer, m66592_timer, 0); |
1591 | m66592->reg = reg; |
1592 | |
1593 | ret = request_irq(irq: ires->start, handler: m66592_irq, IRQF_SHARED, |
1594 | name: udc_name, dev: m66592); |
1595 | if (ret < 0) { |
1596 | pr_err("request_irq error (%d)\n" , ret); |
1597 | goto clean_up; |
1598 | } |
1599 | |
1600 | if (m66592->pdata->on_chip) { |
1601 | snprintf(buf: clk_name, size: sizeof(clk_name), fmt: "usbf%d" , pdev->id); |
1602 | m66592->clk = clk_get(dev: &pdev->dev, id: clk_name); |
1603 | if (IS_ERR(ptr: m66592->clk)) { |
1604 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n" , |
1605 | clk_name); |
1606 | ret = PTR_ERR(ptr: m66592->clk); |
1607 | goto clean_up2; |
1608 | } |
1609 | clk_enable(clk: m66592->clk); |
1610 | } |
1611 | |
1612 | INIT_LIST_HEAD(list: &m66592->gadget.ep_list); |
1613 | m66592->gadget.ep0 = &m66592->ep[0].ep; |
1614 | INIT_LIST_HEAD(list: &m66592->gadget.ep0->ep_list); |
1615 | for (i = 0; i < M66592_MAX_NUM_PIPE; i++) { |
1616 | struct m66592_ep *ep = &m66592->ep[i]; |
1617 | |
1618 | if (i != 0) { |
1619 | INIT_LIST_HEAD(list: &m66592->ep[i].ep.ep_list); |
1620 | list_add_tail(new: &m66592->ep[i].ep.ep_list, |
1621 | head: &m66592->gadget.ep_list); |
1622 | } |
1623 | ep->m66592 = m66592; |
1624 | INIT_LIST_HEAD(list: &ep->queue); |
1625 | ep->ep.name = m66592_ep_name[i]; |
1626 | ep->ep.ops = &m66592_ep_ops; |
1627 | usb_ep_set_maxpacket_limit(ep: &ep->ep, maxpacket_limit: 512); |
1628 | |
1629 | if (i == 0) { |
1630 | ep->ep.caps.type_control = true; |
1631 | } else { |
1632 | ep->ep.caps.type_iso = true; |
1633 | ep->ep.caps.type_bulk = true; |
1634 | ep->ep.caps.type_int = true; |
1635 | } |
1636 | |
1637 | ep->ep.caps.dir_in = true; |
1638 | ep->ep.caps.dir_out = true; |
1639 | } |
1640 | usb_ep_set_maxpacket_limit(ep: &m66592->ep[0].ep, maxpacket_limit: 64); |
1641 | m66592->ep[0].pipenum = 0; |
1642 | m66592->ep[0].fifoaddr = M66592_CFIFO; |
1643 | m66592->ep[0].fifosel = M66592_CFIFOSEL; |
1644 | m66592->ep[0].fifoctr = M66592_CFIFOCTR; |
1645 | m66592->ep[0].fifotrn = 0; |
1646 | m66592->ep[0].pipectr = get_pipectr_addr(0); |
1647 | m66592->pipenum2ep[0] = &m66592->ep[0]; |
1648 | m66592->epaddr2ep[0] = &m66592->ep[0]; |
1649 | |
1650 | m66592->ep0_req = m66592_alloc_request(ep: &m66592->ep[0].ep, GFP_KERNEL); |
1651 | if (m66592->ep0_req == NULL) { |
1652 | ret = -ENOMEM; |
1653 | goto clean_up3; |
1654 | } |
1655 | m66592->ep0_req->complete = nop_completion; |
1656 | |
1657 | init_controller(m66592); |
1658 | |
1659 | ret = usb_add_gadget_udc(parent: &pdev->dev, gadget: &m66592->gadget); |
1660 | if (ret) |
1661 | goto err_add_udc; |
1662 | |
1663 | dev_info(&pdev->dev, "version %s\n" , DRIVER_VERSION); |
1664 | return 0; |
1665 | |
1666 | err_add_udc: |
1667 | m66592_free_request(ep: &m66592->ep[0].ep, req: m66592->ep0_req); |
1668 | m66592->ep0_req = NULL; |
1669 | clean_up3: |
1670 | if (m66592->pdata->on_chip) { |
1671 | clk_disable(clk: m66592->clk); |
1672 | clk_put(clk: m66592->clk); |
1673 | } |
1674 | clean_up2: |
1675 | free_irq(ires->start, m66592); |
1676 | clean_up: |
1677 | if (m66592) { |
1678 | if (m66592->ep0_req) |
1679 | m66592_free_request(ep: &m66592->ep[0].ep, req: m66592->ep0_req); |
1680 | kfree(objp: m66592); |
1681 | } |
1682 | if (reg) |
1683 | iounmap(addr: reg); |
1684 | |
1685 | return ret; |
1686 | } |
1687 | |
1688 | /*-------------------------------------------------------------------------*/ |
1689 | static struct platform_driver m66592_driver = { |
1690 | .probe = m66592_probe, |
1691 | .remove_new = m66592_remove, |
1692 | .driver = { |
1693 | .name = udc_name, |
1694 | }, |
1695 | }; |
1696 | |
1697 | module_platform_driver(m66592_driver); |
1698 | |