Skip to content

Commit

Permalink
usb: renesas_usbhs: fifo became independent from pipe.
Browse files Browse the repository at this point in the history
Current renesas_usbhs has PIO data transfer mode which controls CFIFO.
And it was implemented in pipe.c.
But, fifo control method needs more flexible implementation
to support DMAEngine.
This patch create fifo.c, and it became independent from pipe.c.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Kuninori Morimoto authored and Greg Kroah-Hartman committed Jun 7, 2011
1 parent ad6f2a8 commit e8d548d
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 251 deletions.
2 changes: 1 addition & 1 deletion drivers/usb/renesas_usbhs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o

renesas_usbhs-y := common.o mod.o pipe.o
renesas_usbhs-y := common.o mod.o pipe.o fifo.o

renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_UDC) += mod_gadget.o
1 change: 1 addition & 0 deletions drivers/usb/renesas_usbhs/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct usbhs_priv;

#include "./mod.h"
#include "./pipe.h"
#include "./fifo.h"

/*
*
Expand Down
211 changes: 211 additions & 0 deletions drivers/usb/renesas_usbhs/fifo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/delay.h>
#include <linux/io.h>
#include "./common.h"
#include "./pipe.h"

/*
* FIFO ctrl
*/
static void usbhsf_send_terminator(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);

usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
}

static int usbhsf_fifo_barrier(struct usbhs_priv *priv)
{
int timeout = 1024;

do {
/* The FIFO port is accessible */
if (usbhs_read(priv, CFIFOCTR) & FRDY)
return 0;

udelay(10);
} while (timeout--);

return -EBUSY;
}

static void usbhsf_fifo_clear(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);

if (!usbhs_pipe_is_dcp(pipe))
usbhsf_fifo_barrier(priv);

usbhs_write(priv, CFIFOCTR, BCLR);
}

static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv)
{
return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
}

static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct device *dev = usbhs_priv_to_dev(priv);
int timeout = 1024;
u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
u16 base = usbhs_pipe_number(pipe); /* CURPIPE */

if (usbhs_pipe_is_dcp(pipe))
base |= (1 == write) << 5; /* ISEL */

/* "base" will be used below */
usbhs_write(priv, CFIFOSEL, base | MBW_32);

/* check ISEL and CURPIPE value */
while (timeout--) {
if (base == (mask & usbhs_read(priv, CFIFOSEL)))
return 0;
udelay(10);
}

dev_err(dev, "fifo select error\n");

return -EIO;
}

/*
* PIO fifo functions
*/
int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
{
return usbhsf_fifo_select(pipe, 1);
}

int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
void __iomem *addr = priv->base + CFIFO;
int maxp = usbhs_pipe_get_maxpacket(pipe);
int total_len;
int i, ret;

ret = usbhs_pipe_is_accessible(pipe);
if (ret < 0)
return ret;

ret = usbhsf_fifo_select(pipe, 1);
if (ret < 0)
return ret;

ret = usbhsf_fifo_barrier(priv);
if (ret < 0)
return ret;

len = min(len, maxp);
total_len = len;

/*
* FIXME
*
* 32-bit access only
*/
if (len >= 4 &&
!((unsigned long)buf & 0x03)) {
iowrite32_rep(addr, buf, len / 4);
len %= 4;
buf += total_len - len;
}

/* the rest operation */
for (i = 0; i < len; i++)
iowrite8(buf[i], addr + (0x03 - (i & 0x03)));

if (total_len < maxp)
usbhsf_send_terminator(pipe);

return total_len;
}

int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
{
int ret;

/*
* select pipe and enable it to prepare packet receive
*/
ret = usbhsf_fifo_select(pipe, 0);
if (ret < 0)
return ret;

usbhs_pipe_enable(pipe);

return ret;
}

int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
void __iomem *addr = priv->base + CFIFO;
int rcv_len;
int i, ret;
int total_len;
u32 data = 0;

ret = usbhsf_fifo_select(pipe, 0);
if (ret < 0)
return ret;

ret = usbhsf_fifo_barrier(priv);
if (ret < 0)
return ret;

rcv_len = usbhsf_fifo_rcv_len(priv);

/*
* Buffer clear if Zero-Length packet
*
* see
* "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
*/
if (0 == rcv_len) {
usbhsf_fifo_clear(pipe);
return 0;
}

len = min(rcv_len, len);
total_len = len;

/*
* FIXME
*
* 32-bit access only
*/
if (len >= 4 &&
!((unsigned long)buf & 0x03)) {
ioread32_rep(addr, buf, len / 4);
len %= 4;
buf += rcv_len - len;
}

/* the rest operation */
for (i = 0; i < len; i++) {
if (!(i & 0x03))
data = ioread32(addr);

buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
}

return total_len;
}
30 changes: 30 additions & 0 deletions drivers/usb/renesas_usbhs/fifo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef RENESAS_USB_FIFO_H
#define RENESAS_USB_FIFO_H

#include "common.h"

/*
* fifo
*/
int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe);
int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe);

#endif /* RENESAS_USB_FIFO_H */
16 changes: 8 additions & 8 deletions drivers/usb/renesas_usbhs/mod_gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep,
* - after callback_update,
* - before queue_pop / stage_end
*/
usbhs_fifo_enable(pipe);
usbhs_pipe_enable(pipe);

/*
* all data were sent ?
Expand Down Expand Up @@ -454,7 +454,7 @@ static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep,
int disable = 0;

uep->handler->irq_mask(uep, disable);
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);
usbhsg_queue_pop(uep, ureq, 0);
}

Expand Down Expand Up @@ -546,9 +546,9 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);

if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) {
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);
usbhs_pipe_clear_sequence(pipe);
usbhs_fifo_enable(pipe);
usbhs_pipe_enable(pipe);
}

usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
Expand Down Expand Up @@ -695,7 +695,7 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
ret = gpriv->driver->setup(&gpriv->gadget, &ctrl);

if (ret < 0)
usbhs_fifo_stall(pipe);
usbhs_pipe_stall(pipe);

return ret;
}
Expand Down Expand Up @@ -803,7 +803,7 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
********* assume under spin lock *********
*/

usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);

/*
* disable pipe irq
Expand Down Expand Up @@ -1016,9 +1016,9 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
halt, usbhs_pipe_number(pipe));

if (halt)
usbhs_fifo_stall(pipe);
usbhs_pipe_stall(pipe);
else
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);

if (halt && wedge)
usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE);
Expand Down
Loading

0 comments on commit e8d548d

Please sign in to comment.