diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2011-06-06 01:18:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-06-07 12:10:09 -0400 |
commit | d77e3f4e1743834c7b4acb54004ffd7f57c82582 (patch) | |
tree | 5ef953674c897b32134578654bc679e41039bfa9 /drivers/usb/renesas_usbhs | |
parent | d3af90a5e4e8fb7a93d408799682e566c9270808 (diff) |
usb: renesas_usbhs: add pipe/fifo link
renesas_usbhs has CFIFO which is for PIO transfer,
and D0FIFO/D1FIFO which are for DMA transfer.
The pipe selects one of these fifo when it send/recv data.
But fifo must not be selected to different pipe in same time.
This patch add pipe/fifo link for each other,
and fifo is not selected by another pipe until it is unselected.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.c | 48 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.h | 2 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.c | 13 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.h | 4 |
4 files changed, 55 insertions, 12 deletions
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 53e2b35dd325..8852423313a3 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c | |||
@@ -21,6 +21,8 @@ | |||
21 | 21 | ||
22 | #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) | 22 | #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) |
23 | 23 | ||
24 | #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ | ||
25 | |||
24 | /* | 26 | /* |
25 | * packet info function | 27 | * packet info function |
26 | */ | 28 | */ |
@@ -237,6 +239,15 @@ static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, | |||
237 | return usbhs_read(priv, fifo->ctr) & DTLN_MASK; | 239 | return usbhs_read(priv, fifo->ctr) & DTLN_MASK; |
238 | } | 240 | } |
239 | 241 | ||
242 | static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, | ||
243 | struct usbhs_fifo *fifo) | ||
244 | { | ||
245 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | ||
246 | |||
247 | usbhs_pipe_select_fifo(pipe, NULL); | ||
248 | usbhs_write(priv, fifo->sel, 0); | ||
249 | } | ||
250 | |||
240 | static int usbhsf_fifo_select(struct usbhs_pipe *pipe, | 251 | static int usbhsf_fifo_select(struct usbhs_pipe *pipe, |
241 | struct usbhs_fifo *fifo, | 252 | struct usbhs_fifo *fifo, |
242 | int write) | 253 | int write) |
@@ -247,6 +258,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe, | |||
247 | u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ | 258 | u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ |
248 | u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ | 259 | u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ |
249 | 260 | ||
261 | if (usbhs_pipe_is_busy(pipe) || | ||
262 | usbhsf_fifo_is_busy(fifo)) | ||
263 | return -EBUSY; | ||
264 | |||
250 | if (usbhs_pipe_is_dcp(pipe)) | 265 | if (usbhs_pipe_is_dcp(pipe)) |
251 | base |= (1 == write) << 5; /* ISEL */ | 266 | base |= (1 == write) << 5; /* ISEL */ |
252 | 267 | ||
@@ -255,8 +270,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe, | |||
255 | 270 | ||
256 | /* check ISEL and CURPIPE value */ | 271 | /* check ISEL and CURPIPE value */ |
257 | while (timeout--) { | 272 | while (timeout--) { |
258 | if (base == (mask & usbhs_read(priv, fifo->sel))) | 273 | if (base == (mask & usbhs_read(priv, fifo->sel))) { |
274 | usbhs_pipe_select_fifo(pipe, fifo); | ||
259 | return 0; | 275 | return 0; |
276 | } | ||
260 | udelay(10); | 277 | udelay(10); |
261 | } | 278 | } |
262 | 279 | ||
@@ -283,7 +300,7 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done) | |||
283 | 300 | ||
284 | ret = usbhsf_fifo_select(pipe, fifo, 1); | 301 | ret = usbhsf_fifo_select(pipe, fifo, 1); |
285 | if (ret < 0) | 302 | if (ret < 0) |
286 | goto usbhs_fifo_write_busy; | 303 | return 0; |
287 | 304 | ||
288 | ret = usbhs_pipe_is_accessible(pipe); | 305 | ret = usbhs_pipe_is_accessible(pipe); |
289 | if (ret < 0) | 306 | if (ret < 0) |
@@ -347,9 +364,13 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done) | |||
347 | usbhs_dcp_control_transfer_done(pipe); | 364 | usbhs_dcp_control_transfer_done(pipe); |
348 | } | 365 | } |
349 | 366 | ||
367 | usbhsf_fifo_unselect(pipe, fifo); | ||
368 | |||
350 | return 0; | 369 | return 0; |
351 | 370 | ||
352 | usbhs_fifo_write_busy: | 371 | usbhs_fifo_write_busy: |
372 | usbhsf_fifo_unselect(pipe, fifo); | ||
373 | |||
353 | /* | 374 | /* |
354 | * pipe is busy. | 375 | * pipe is busy. |
355 | * retry in interrupt | 376 | * retry in interrupt |
@@ -367,16 +388,13 @@ struct usbhs_pkt_handle usbhs_fifo_push_handler = { | |||
367 | static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) | 388 | static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) |
368 | { | 389 | { |
369 | struct usbhs_pipe *pipe = pkt->pipe; | 390 | struct usbhs_pipe *pipe = pkt->pipe; |
370 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | 391 | |
371 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ | 392 | if (usbhs_pipe_is_busy(pipe)) |
372 | int ret; | 393 | return 0; |
373 | 394 | ||
374 | /* | 395 | /* |
375 | * select pipe and enable it to prepare packet receive | 396 | * pipe enable to prepare packet receive |
376 | */ | 397 | */ |
377 | ret = usbhsf_fifo_select(pipe, fifo, 0); | ||
378 | if (ret < 0) | ||
379 | return ret; | ||
380 | 398 | ||
381 | usbhs_pipe_enable(pipe); | 399 | usbhs_pipe_enable(pipe); |
382 | usbhsf_rx_irq_ctrl(pipe, 1); | 400 | usbhsf_rx_irq_ctrl(pipe, 1); |
@@ -400,11 +418,11 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done) | |||
400 | 418 | ||
401 | ret = usbhsf_fifo_select(pipe, fifo, 0); | 419 | ret = usbhsf_fifo_select(pipe, fifo, 0); |
402 | if (ret < 0) | 420 | if (ret < 0) |
403 | return ret; | 421 | return 0; |
404 | 422 | ||
405 | ret = usbhsf_fifo_barrier(priv, fifo); | 423 | ret = usbhsf_fifo_barrier(priv, fifo); |
406 | if (ret < 0) | 424 | if (ret < 0) |
407 | return ret; | 425 | goto usbhs_fifo_read_busy; |
408 | 426 | ||
409 | rcv_len = usbhsf_fifo_rcv_len(priv, fifo); | 427 | rcv_len = usbhsf_fifo_rcv_len(priv, fifo); |
410 | 428 | ||
@@ -457,7 +475,10 @@ usbhs_fifo_read_end: | |||
457 | usbhs_pipe_number(pipe), | 475 | usbhs_pipe_number(pipe), |
458 | pkt->length, pkt->actual, *is_done, pkt->zero); | 476 | pkt->length, pkt->actual, *is_done, pkt->zero); |
459 | 477 | ||
460 | return 0; | 478 | usbhs_fifo_read_busy: |
479 | usbhsf_fifo_unselect(pipe, fifo); | ||
480 | |||
481 | return ret; | ||
461 | } | 482 | } |
462 | 483 | ||
463 | struct usbhs_pkt_handle usbhs_fifo_pop_handler = { | 484 | struct usbhs_pkt_handle usbhs_fifo_pop_handler = { |
@@ -551,11 +572,14 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv, | |||
551 | void usbhs_fifo_init(struct usbhs_priv *priv) | 572 | void usbhs_fifo_init(struct usbhs_priv *priv) |
552 | { | 573 | { |
553 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | 574 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); |
575 | struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); | ||
554 | 576 | ||
555 | mod->irq_empty = usbhsf_irq_empty; | 577 | mod->irq_empty = usbhsf_irq_empty; |
556 | mod->irq_ready = usbhsf_irq_ready; | 578 | mod->irq_ready = usbhsf_irq_ready; |
557 | mod->irq_bempsts = 0; | 579 | mod->irq_bempsts = 0; |
558 | mod->irq_brdysts = 0; | 580 | mod->irq_brdysts = 0; |
581 | |||
582 | cfifo->pipe = NULL; | ||
559 | } | 583 | } |
560 | 584 | ||
561 | void usbhs_fifo_quit(struct usbhs_priv *priv) | 585 | void usbhs_fifo_quit(struct usbhs_priv *priv) |
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 04d000ae7bdc..4292f8c9e1f7 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h | |||
@@ -23,6 +23,8 @@ struct usbhs_fifo { | |||
23 | u32 port; /* xFIFO */ | 23 | u32 port; /* xFIFO */ |
24 | u32 sel; /* xFIFOSEL */ | 24 | u32 sel; /* xFIFOSEL */ |
25 | u32 ctr; /* xFIFOCTR */ | 25 | u32 ctr; /* xFIFOCTR */ |
26 | |||
27 | struct usbhs_pipe *pipe; | ||
26 | }; | 28 | }; |
27 | 29 | ||
28 | struct usbhs_fifo_info { | 30 | struct usbhs_fifo_info { |
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 56137d59e3b2..c0505876fd8c 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c | |||
@@ -562,6 +562,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv, | |||
562 | info->bufnmb_last++; | 562 | info->bufnmb_last++; |
563 | 563 | ||
564 | usbhsp_flags_init(pipe); | 564 | usbhsp_flags_init(pipe); |
565 | pipe->fifo = NULL; | ||
565 | pipe->mod_private = NULL; | 566 | pipe->mod_private = NULL; |
566 | INIT_LIST_HEAD(&pipe->list); | 567 | INIT_LIST_HEAD(&pipe->list); |
567 | 568 | ||
@@ -620,6 +621,18 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, | |||
620 | return pipe; | 621 | return pipe; |
621 | } | 622 | } |
622 | 623 | ||
624 | void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) | ||
625 | { | ||
626 | if (pipe->fifo) | ||
627 | pipe->fifo->pipe = NULL; | ||
628 | |||
629 | pipe->fifo = fifo; | ||
630 | |||
631 | if (fifo) | ||
632 | fifo->pipe = pipe; | ||
633 | } | ||
634 | |||
635 | |||
623 | /* | 636 | /* |
624 | * dcp control | 637 | * dcp control |
625 | */ | 638 | */ |
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 20e3cf46f70c..484adbed6dfb 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h | |||
@@ -27,6 +27,7 @@ struct usbhs_pipe { | |||
27 | u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */ | 27 | u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */ |
28 | 28 | ||
29 | struct usbhs_priv *priv; | 29 | struct usbhs_priv *priv; |
30 | struct usbhs_fifo *fifo; | ||
30 | struct list_head list; | 31 | struct list_head list; |
31 | 32 | ||
32 | u32 flags; | 33 | u32 flags; |
@@ -88,10 +89,13 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); | |||
88 | void usbhs_pipe_enable(struct usbhs_pipe *pipe); | 89 | void usbhs_pipe_enable(struct usbhs_pipe *pipe); |
89 | void usbhs_pipe_disable(struct usbhs_pipe *pipe); | 90 | void usbhs_pipe_disable(struct usbhs_pipe *pipe); |
90 | void usbhs_pipe_stall(struct usbhs_pipe *pipe); | 91 | void usbhs_pipe_stall(struct usbhs_pipe *pipe); |
92 | void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); | ||
91 | 93 | ||
92 | #define usbhs_pipe_to_priv(p) ((p)->priv) | 94 | #define usbhs_pipe_to_priv(p) ((p)->priv) |
93 | #define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe) | 95 | #define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe) |
94 | #define usbhs_pipe_is_dcp(p) ((p)->priv->pipe_info.pipe == (p)) | 96 | #define usbhs_pipe_is_dcp(p) ((p)->priv->pipe_info.pipe == (p)) |
97 | #define usbhs_pipe_to_fifo(p) ((p)->fifo) | ||
98 | #define usbhs_pipe_is_busy(p) usbhs_pipe_to_fifo(p) | ||
95 | 99 | ||
96 | /* | 100 | /* |
97 | * dcp control | 101 | * dcp control |