summaryrefslogtreecommitdiffstats
path: root/drivers/usb/renesas_usbhs/fifo.c
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2011-06-06 14:18:50 +0900
committerGreg Kroah-Hartman <gregkh@suse.de>2011-06-07 09:10:09 -0700
commitd77e3f4e1743834c7b4acb54004ffd7f57c82582 (patch)
tree5ef953674c897b32134578654bc679e41039bfa9 /drivers/usb/renesas_usbhs/fifo.c
parentd3af90a5e4e8fb7a93d408799682e566c9270808 (diff)
downloadlinux-d77e3f4e1743834c7b4acb54004ffd7f57c82582.tar.gz
linux-d77e3f4e1743834c7b4acb54004ffd7f57c82582.tar.bz2
linux-d77e3f4e1743834c7b4acb54004ffd7f57c82582.zip
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/fifo.c')
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c48
1 files changed, 36 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 @@
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
+#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
+
/*
* packet info function
*/
@@ -237,6 +239,15 @@ static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,
return usbhs_read(priv, fifo->ctr) & DTLN_MASK;
}
+static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe,
+ struct usbhs_fifo *fifo)
+{
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+
+ usbhs_pipe_select_fifo(pipe, NULL);
+ usbhs_write(priv, fifo->sel, 0);
+}
+
static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
struct usbhs_fifo *fifo,
int write)
@@ -247,6 +258,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
u16 base = usbhs_pipe_number(pipe); /* CURPIPE */
+ if (usbhs_pipe_is_busy(pipe) ||
+ usbhsf_fifo_is_busy(fifo))
+ return -EBUSY;
+
if (usbhs_pipe_is_dcp(pipe))
base |= (1 == write) << 5; /* ISEL */
@@ -255,8 +270,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
/* check ISEL and CURPIPE value */
while (timeout--) {
- if (base == (mask & usbhs_read(priv, fifo->sel)))
+ if (base == (mask & usbhs_read(priv, fifo->sel))) {
+ usbhs_pipe_select_fifo(pipe, fifo);
return 0;
+ }
udelay(10);
}
@@ -283,7 +300,7 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done)
ret = usbhsf_fifo_select(pipe, fifo, 1);
if (ret < 0)
- goto usbhs_fifo_write_busy;
+ return 0;
ret = usbhs_pipe_is_accessible(pipe);
if (ret < 0)
@@ -347,9 +364,13 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done)
usbhs_dcp_control_transfer_done(pipe);
}
+ usbhsf_fifo_unselect(pipe, fifo);
+
return 0;
usbhs_fifo_write_busy:
+ usbhsf_fifo_unselect(pipe, fifo);
+
/*
* pipe is busy.
* retry in interrupt
@@ -367,16 +388,13 @@ struct usbhs_pkt_handle usbhs_fifo_push_handler = {
static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
{
struct usbhs_pipe *pipe = pkt->pipe;
- struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
- struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */
- int ret;
+
+ if (usbhs_pipe_is_busy(pipe))
+ return 0;
/*
- * select pipe and enable it to prepare packet receive
+ * pipe enable to prepare packet receive
*/
- ret = usbhsf_fifo_select(pipe, fifo, 0);
- if (ret < 0)
- return ret;
usbhs_pipe_enable(pipe);
usbhsf_rx_irq_ctrl(pipe, 1);
@@ -400,11 +418,11 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done)
ret = usbhsf_fifo_select(pipe, fifo, 0);
if (ret < 0)
- return ret;
+ return 0;
ret = usbhsf_fifo_barrier(priv, fifo);
if (ret < 0)
- return ret;
+ goto usbhs_fifo_read_busy;
rcv_len = usbhsf_fifo_rcv_len(priv, fifo);
@@ -457,7 +475,10 @@ usbhs_fifo_read_end:
usbhs_pipe_number(pipe),
pkt->length, pkt->actual, *is_done, pkt->zero);
- return 0;
+usbhs_fifo_read_busy:
+ usbhsf_fifo_unselect(pipe, fifo);
+
+ return ret;
}
struct usbhs_pkt_handle usbhs_fifo_pop_handler = {
@@ -551,11 +572,14 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv,
void usbhs_fifo_init(struct usbhs_priv *priv)
{
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
+ struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv);
mod->irq_empty = usbhsf_irq_empty;
mod->irq_ready = usbhsf_irq_ready;
mod->irq_bempsts = 0;
mod->irq_brdysts = 0;
+
+ cfifo->pipe = NULL;
}
void usbhs_fifo_quit(struct usbhs_priv *priv)