usb: gadget: r8a66597-udc: add support for SUDMAC
SH7757 has a USB function with internal DMA controller (SUDMAC). This patch supports the SUDMAC. The SUDMAC is incompatible with general-purpose DMAC. So, it doesn't use dmaengine. Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Родитель
12158f4280
Коммит
b8a56e17e1
|
@ -18,13 +18,14 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include "r8a66597-udc.h"
|
||||
|
||||
#define DRIVER_VERSION "2009-08-18"
|
||||
#define DRIVER_VERSION "2011-09-26"
|
||||
|
||||
static const char udc_name[] = "r8a66597_udc";
|
||||
static const char *r8a66597_ep_name[] = {
|
||||
|
@ -184,6 +185,54 @@ static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum)
|
|||
}
|
||||
}
|
||||
|
||||
static void control_reg_sqset(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
pipe_stop(r8a66597, pipenum);
|
||||
|
||||
if (pipenum == 0) {
|
||||
r8a66597_bset(r8a66597, SQSET, DCPCTR);
|
||||
} else if (pipenum < R8A66597_MAX_NUM_PIPE) {
|
||||
offset = get_pipectr_addr(pipenum);
|
||||
r8a66597_bset(r8a66597, SQSET, offset);
|
||||
} else {
|
||||
dev_err(r8a66597_to_dev(r8a66597),
|
||||
"unexpect pipe num(%d)\n", pipenum);
|
||||
}
|
||||
}
|
||||
|
||||
static u16 control_reg_sqmon(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
if (pipenum == 0) {
|
||||
return r8a66597_read(r8a66597, DCPCTR) & SQMON;
|
||||
} else if (pipenum < R8A66597_MAX_NUM_PIPE) {
|
||||
offset = get_pipectr_addr(pipenum);
|
||||
return r8a66597_read(r8a66597, offset) & SQMON;
|
||||
} else {
|
||||
dev_err(r8a66597_to_dev(r8a66597),
|
||||
"unexpect pipe num(%d)\n", pipenum);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 save_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
return control_reg_sqmon(r8a66597, pipenum);
|
||||
}
|
||||
|
||||
static void restore_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum,
|
||||
u16 toggle)
|
||||
{
|
||||
if (toggle)
|
||||
control_reg_sqset(r8a66597, pipenum);
|
||||
else
|
||||
control_reg_sqclr(r8a66597, pipenum);
|
||||
}
|
||||
|
||||
static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
u16 tmp;
|
||||
|
@ -220,18 +269,51 @@ static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
|
|||
return MBW_16;
|
||||
}
|
||||
|
||||
static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum,
|
||||
u16 isel, u16 fifosel)
|
||||
{
|
||||
u16 tmp, mask, loop;
|
||||
int i = 0;
|
||||
|
||||
if (!pipenum) {
|
||||
mask = ISEL | CURPIPE;
|
||||
loop = isel;
|
||||
} else {
|
||||
mask = CURPIPE;
|
||||
loop = pipenum;
|
||||
}
|
||||
r8a66597_mdfy(r8a66597, loop, mask, fifosel);
|
||||
|
||||
do {
|
||||
tmp = r8a66597_read(r8a66597, fifosel);
|
||||
if (i++ > 1000000) {
|
||||
dev_err(r8a66597_to_dev(r8a66597),
|
||||
"r8a66597: register%x, loop %x "
|
||||
"is timeout\n", fifosel, loop);
|
||||
break;
|
||||
}
|
||||
ndelay(1);
|
||||
} while ((tmp & mask) != loop);
|
||||
}
|
||||
|
||||
static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
|
||||
|
||||
if (ep->use_dma)
|
||||
return;
|
||||
r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
|
||||
|
||||
r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel);
|
||||
|
||||
ndelay(450);
|
||||
|
||||
r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel);
|
||||
if (r8a66597_is_sudmac(r8a66597) && ep->use_dma)
|
||||
r8a66597_bclr(r8a66597, mbw_value(r8a66597), ep->fifosel);
|
||||
else
|
||||
r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel);
|
||||
|
||||
if (ep->use_dma)
|
||||
r8a66597_bset(r8a66597, DREQE, ep->fifosel);
|
||||
}
|
||||
|
||||
static int pipe_buffer_setting(struct r8a66597 *r8a66597,
|
||||
|
@ -336,9 +418,15 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597,
|
|||
ep->fifoaddr = CFIFO;
|
||||
ep->fifosel = CFIFOSEL;
|
||||
ep->fifoctr = CFIFOCTR;
|
||||
ep->fifotrn = 0;
|
||||
|
||||
ep->pipectr = get_pipectr_addr(pipenum);
|
||||
if (is_bulk_pipe(pipenum) || is_isoc_pipe(pipenum)) {
|
||||
ep->pipetre = get_pipetre_addr(pipenum);
|
||||
ep->pipetrn = get_pipetrn_addr(pipenum);
|
||||
} else {
|
||||
ep->pipetre = 0;
|
||||
ep->pipetrn = 0;
|
||||
}
|
||||
ep->pipenum = pipenum;
|
||||
ep->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
r8a66597->pipenum2ep[pipenum] = ep;
|
||||
|
@ -498,6 +586,124 @@ static void start_ep0_write(struct r8a66597_ep *ep,
|
|||
}
|
||||
}
|
||||
|
||||
static void disable_fifosel(struct r8a66597 *r8a66597, u16 pipenum,
|
||||
u16 fifosel)
|
||||
{
|
||||
u16 tmp;
|
||||
|
||||
tmp = r8a66597_read(r8a66597, fifosel) & CURPIPE;
|
||||
if (tmp == pipenum)
|
||||
r8a66597_change_curpipe(r8a66597, 0, 0, fifosel);
|
||||
}
|
||||
|
||||
static void change_bfre_mode(struct r8a66597 *r8a66597, u16 pipenum,
|
||||
int enable)
|
||||
{
|
||||
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
|
||||
u16 tmp, toggle;
|
||||
|
||||
/* check current BFRE bit */
|
||||
r8a66597_write(r8a66597, pipenum, PIPESEL);
|
||||
tmp = r8a66597_read(r8a66597, PIPECFG) & R8A66597_BFRE;
|
||||
if ((enable && tmp) || (!enable && !tmp))
|
||||
return;
|
||||
|
||||
/* change BFRE bit */
|
||||
pipe_stop(r8a66597, pipenum);
|
||||
disable_fifosel(r8a66597, pipenum, CFIFOSEL);
|
||||
disable_fifosel(r8a66597, pipenum, D0FIFOSEL);
|
||||
disable_fifosel(r8a66597, pipenum, D1FIFOSEL);
|
||||
|
||||
toggle = save_usb_toggle(r8a66597, pipenum);
|
||||
|
||||
r8a66597_write(r8a66597, pipenum, PIPESEL);
|
||||
if (enable)
|
||||
r8a66597_bset(r8a66597, R8A66597_BFRE, PIPECFG);
|
||||
else
|
||||
r8a66597_bclr(r8a66597, R8A66597_BFRE, PIPECFG);
|
||||
|
||||
/* initialize for internal BFRE flag */
|
||||
r8a66597_bset(r8a66597, ACLRM, ep->pipectr);
|
||||
r8a66597_bclr(r8a66597, ACLRM, ep->pipectr);
|
||||
|
||||
restore_usb_toggle(r8a66597, pipenum, toggle);
|
||||
}
|
||||
|
||||
static int sudmac_alloc_channel(struct r8a66597 *r8a66597,
|
||||
struct r8a66597_ep *ep,
|
||||
struct r8a66597_request *req)
|
||||
{
|
||||
struct r8a66597_dma *dma;
|
||||
|
||||
if (!r8a66597_is_sudmac(r8a66597))
|
||||
return -ENODEV;
|
||||
|
||||
/* Check transfer type */
|
||||
if (!is_bulk_pipe(ep->pipenum))
|
||||
return -EIO;
|
||||
|
||||
if (r8a66597->dma.used)
|
||||
return -EBUSY;
|
||||
|
||||
/* set SUDMAC parameters */
|
||||
dma = &r8a66597->dma;
|
||||
dma->used = 1;
|
||||
if (ep->desc->bEndpointAddress & USB_DIR_IN) {
|
||||
dma->dir = 1;
|
||||
} else {
|
||||
dma->dir = 0;
|
||||
change_bfre_mode(r8a66597, ep->pipenum, 1);
|
||||
}
|
||||
|
||||
/* set r8a66597_ep paramters */
|
||||
ep->use_dma = 1;
|
||||
ep->dma = dma;
|
||||
ep->fifoaddr = D0FIFO;
|
||||
ep->fifosel = D0FIFOSEL;
|
||||
ep->fifoctr = D0FIFOCTR;
|
||||
|
||||
/* dma mapping */
|
||||
req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597),
|
||||
req->req.buf, req->req.length,
|
||||
dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sudmac_free_channel(struct r8a66597 *r8a66597,
|
||||
struct r8a66597_ep *ep,
|
||||
struct r8a66597_request *req)
|
||||
{
|
||||
if (!r8a66597_is_sudmac(r8a66597))
|
||||
return;
|
||||
|
||||
dma_unmap_single(r8a66597_to_dev(ep->r8a66597),
|
||||
req->req.dma, req->req.length,
|
||||
ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
|
||||
r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
|
||||
r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel);
|
||||
|
||||
ep->dma->used = 0;
|
||||
ep->use_dma = 0;
|
||||
ep->fifoaddr = CFIFO;
|
||||
ep->fifosel = CFIFOSEL;
|
||||
ep->fifoctr = CFIFOCTR;
|
||||
}
|
||||
|
||||
static void sudmac_start(struct r8a66597 *r8a66597, struct r8a66597_ep *ep,
|
||||
struct r8a66597_request *req)
|
||||
{
|
||||
BUG_ON(req->req.length == 0);
|
||||
|
||||
r8a66597_sudmac_write(r8a66597, LBA_WAIT, CH0CFG);
|
||||
r8a66597_sudmac_write(r8a66597, req->req.dma, CH0BA);
|
||||
r8a66597_sudmac_write(r8a66597, req->req.length, CH0BBC);
|
||||
r8a66597_sudmac_write(r8a66597, CH0ENDE, DINTCTRL);
|
||||
|
||||
r8a66597_sudmac_write(r8a66597, DEN, CH0DEN);
|
||||
}
|
||||
|
||||
static void start_packet_write(struct r8a66597_ep *ep,
|
||||
struct r8a66597_request *req)
|
||||
{
|
||||
|
@ -508,11 +714,29 @@ static void start_packet_write(struct r8a66597_ep *ep,
|
|||
disable_irq_empty(r8a66597, ep->pipenum);
|
||||
pipe_start(r8a66597, ep->pipenum);
|
||||
|
||||
tmp = r8a66597_read(r8a66597, ep->fifoctr);
|
||||
if (unlikely((tmp & FRDY) == 0))
|
||||
pipe_irq_enable(r8a66597, ep->pipenum);
|
||||
else
|
||||
irq_packet_write(ep, req);
|
||||
if (req->req.length == 0) {
|
||||
transfer_complete(ep, req, 0);
|
||||
} else {
|
||||
r8a66597_write(r8a66597, ~(1 << ep->pipenum), BRDYSTS);
|
||||
if (sudmac_alloc_channel(r8a66597, ep, req) < 0) {
|
||||
/* PIO mode */
|
||||
pipe_change(r8a66597, ep->pipenum);
|
||||
disable_irq_empty(r8a66597, ep->pipenum);
|
||||
pipe_start(r8a66597, ep->pipenum);
|
||||
tmp = r8a66597_read(r8a66597, ep->fifoctr);
|
||||
if (unlikely((tmp & FRDY) == 0))
|
||||
pipe_irq_enable(r8a66597, ep->pipenum);
|
||||
else
|
||||
irq_packet_write(ep, req);
|
||||
} else {
|
||||
/* DMA mode */
|
||||
pipe_change(r8a66597, ep->pipenum);
|
||||
disable_irq_nrdy(r8a66597, ep->pipenum);
|
||||
pipe_start(r8a66597, ep->pipenum);
|
||||
enable_irq_nrdy(r8a66597, ep->pipenum);
|
||||
sudmac_start(r8a66597, ep, req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void start_packet_read(struct r8a66597_ep *ep,
|
||||
|
@ -527,17 +751,26 @@ static void start_packet_read(struct r8a66597_ep *ep,
|
|||
pipe_start(r8a66597, pipenum);
|
||||
pipe_irq_enable(r8a66597, pipenum);
|
||||
} else {
|
||||
if (ep->use_dma) {
|
||||
r8a66597_bset(r8a66597, TRCLR, ep->fifosel);
|
||||
pipe_change(r8a66597, pipenum);
|
||||
r8a66597_bset(r8a66597, TRENB, ep->fifosel);
|
||||
pipe_stop(r8a66597, pipenum);
|
||||
if (ep->pipetre) {
|
||||
enable_irq_nrdy(r8a66597, pipenum);
|
||||
r8a66597_write(r8a66597, TRCLR, ep->pipetre);
|
||||
r8a66597_write(r8a66597,
|
||||
(req->req.length + ep->ep.maxpacket - 1)
|
||||
/ ep->ep.maxpacket,
|
||||
ep->fifotrn);
|
||||
DIV_ROUND_UP(req->req.length, ep->ep.maxpacket),
|
||||
ep->pipetrn);
|
||||
r8a66597_bset(r8a66597, TRENB, ep->pipetre);
|
||||
}
|
||||
|
||||
if (sudmac_alloc_channel(r8a66597, ep, req) < 0) {
|
||||
/* PIO mode */
|
||||
change_bfre_mode(r8a66597, ep->pipenum, 0);
|
||||
pipe_start(r8a66597, pipenum); /* trigger once */
|
||||
pipe_irq_enable(r8a66597, pipenum);
|
||||
} else {
|
||||
pipe_change(r8a66597, pipenum);
|
||||
sudmac_start(r8a66597, ep, req);
|
||||
pipe_start(r8a66597, pipenum); /* trigger once */
|
||||
}
|
||||
pipe_start(r8a66597, pipenum); /* trigger once */
|
||||
pipe_irq_enable(r8a66597, pipenum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -694,6 +927,9 @@ __acquires(r8a66597->lock)
|
|||
if (!list_empty(&ep->queue))
|
||||
restart = 1;
|
||||
|
||||
if (ep->use_dma)
|
||||
sudmac_free_channel(ep->r8a66597, ep, req);
|
||||
|
||||
spin_unlock(&ep->r8a66597->lock);
|
||||
req->req.complete(&ep->ep, &req->req);
|
||||
spin_lock(&ep->r8a66597->lock);
|
||||
|
@ -1170,6 +1406,65 @@ __acquires(r8a66597->lock)
|
|||
}
|
||||
}
|
||||
|
||||
static void sudmac_finish(struct r8a66597 *r8a66597, struct r8a66597_ep *ep)
|
||||
{
|
||||
u16 pipenum;
|
||||
struct r8a66597_request *req;
|
||||
u32 len;
|
||||
int i = 0;
|
||||
|
||||
pipenum = ep->pipenum;
|
||||
pipe_change(r8a66597, pipenum);
|
||||
|
||||
while (!(r8a66597_read(r8a66597, ep->fifoctr) & FRDY)) {
|
||||
udelay(1);
|
||||
if (unlikely(i++ >= 10000)) { /* timeout = 10 msec */
|
||||
dev_err(r8a66597_to_dev(r8a66597),
|
||||
"%s: FRDY was not set (%d)\n",
|
||||
__func__, pipenum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
r8a66597_bset(r8a66597, BCLR, ep->fifoctr);
|
||||
req = get_request_from_ep(ep);
|
||||
|
||||
/* prepare parameters */
|
||||
len = r8a66597_sudmac_read(r8a66597, CH0CBC);
|
||||
req->req.actual += len;
|
||||
|
||||
/* clear */
|
||||
r8a66597_sudmac_write(r8a66597, CH0STCLR, DSTSCLR);
|
||||
|
||||
/* check transfer finish */
|
||||
if ((!req->req.zero && (req->req.actual == req->req.length))
|
||||
|| (len % ep->ep.maxpacket)) {
|
||||
if (ep->dma->dir) {
|
||||
disable_irq_ready(r8a66597, pipenum);
|
||||
enable_irq_empty(r8a66597, pipenum);
|
||||
} else {
|
||||
/* Clear the interrupt flag for next transfer */
|
||||
r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
|
||||
transfer_complete(ep, req, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void r8a66597_sudmac_irq(struct r8a66597 *r8a66597)
|
||||
{
|
||||
u32 irqsts;
|
||||
struct r8a66597_ep *ep;
|
||||
u16 pipenum;
|
||||
|
||||
irqsts = r8a66597_sudmac_read(r8a66597, DINTSTS);
|
||||
if (irqsts & CH0ENDS) {
|
||||
r8a66597_sudmac_write(r8a66597, CH0ENDC, DINTSTSCLR);
|
||||
pipenum = (r8a66597_read(r8a66597, D0FIFOSEL) & CURPIPE);
|
||||
ep = r8a66597->pipenum2ep[pipenum];
|
||||
sudmac_finish(r8a66597, ep);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = _r8a66597;
|
||||
|
@ -1180,6 +1475,9 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
|
|||
u16 savepipe;
|
||||
u16 mask0;
|
||||
|
||||
if (r8a66597_is_sudmac(r8a66597))
|
||||
r8a66597_sudmac_irq(r8a66597);
|
||||
|
||||
spin_lock(&r8a66597->lock);
|
||||
|
||||
intsts0 = r8a66597_read(r8a66597, INTSTS0);
|
||||
|
@ -1556,6 +1854,8 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
|
|||
usb_del_gadget_udc(&r8a66597->gadget);
|
||||
del_timer_sync(&r8a66597->timer);
|
||||
iounmap(r8a66597->reg);
|
||||
if (r8a66597->pdata->sudmac)
|
||||
iounmap(r8a66597->sudmac_reg);
|
||||
free_irq(platform_get_irq(pdev, 0), r8a66597);
|
||||
r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
|
||||
#ifdef CONFIG_HAVE_CLK
|
||||
|
@ -1572,6 +1872,26 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r)
|
|||
{
|
||||
}
|
||||
|
||||
static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "platform_get_resource error(sudmac).\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r8a66597->sudmac_reg = ioremap(res->start, resource_size(res));
|
||||
if (r8a66597->sudmac_reg == NULL) {
|
||||
dev_err(&pdev->dev, "ioremap error(sudmac).\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
{
|
||||
#ifdef CONFIG_HAVE_CLK
|
||||
|
@ -1649,6 +1969,11 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
|||
clk_enable(r8a66597->clk);
|
||||
}
|
||||
#endif
|
||||
if (r8a66597->pdata->sudmac) {
|
||||
ret = r8a66597_sudmac_ioremap(r8a66597, pdev);
|
||||
if (ret < 0)
|
||||
goto clean_up2;
|
||||
}
|
||||
|
||||
disable_controller(r8a66597); /* make sure controller is disabled */
|
||||
|
||||
|
@ -1681,7 +2006,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
|||
r8a66597->ep[0].fifoaddr = CFIFO;
|
||||
r8a66597->ep[0].fifosel = CFIFOSEL;
|
||||
r8a66597->ep[0].fifoctr = CFIFOCTR;
|
||||
r8a66597->ep[0].fifotrn = 0;
|
||||
r8a66597->ep[0].pipectr = get_pipectr_addr(0);
|
||||
r8a66597->pipenum2ep[0] = &r8a66597->ep[0];
|
||||
r8a66597->epaddr2ep[0] = &r8a66597->ep[0];
|
||||
|
@ -1714,6 +2038,8 @@ clean_up2:
|
|||
#endif
|
||||
clean_up:
|
||||
if (r8a66597) {
|
||||
if (r8a66597->sudmac_reg)
|
||||
iounmap(r8a66597->sudmac_reg);
|
||||
if (r8a66597->ep0_req)
|
||||
r8a66597_free_request(&r8a66597->ep[0].ep,
|
||||
r8a66597->ep0_req);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \
|
||||
(pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC)))
|
||||
|
||||
#define r8a66597_is_sudmac(r8a66597) (r8a66597->pdata->sudmac)
|
||||
struct r8a66597_pipe_info {
|
||||
u16 pipe;
|
||||
u16 epnum;
|
||||
|
@ -60,6 +61,7 @@ struct r8a66597_request {
|
|||
struct r8a66597_ep {
|
||||
struct usb_ep ep;
|
||||
struct r8a66597 *r8a66597;
|
||||
struct r8a66597_dma *dma;
|
||||
|
||||
struct list_head queue;
|
||||
unsigned busy:1;
|
||||
|
@ -75,13 +77,20 @@ struct r8a66597_ep {
|
|||
unsigned char fifoaddr;
|
||||
unsigned char fifosel;
|
||||
unsigned char fifoctr;
|
||||
unsigned char fifotrn;
|
||||
unsigned char pipectr;
|
||||
unsigned char pipetre;
|
||||
unsigned char pipetrn;
|
||||
};
|
||||
|
||||
struct r8a66597_dma {
|
||||
unsigned used:1;
|
||||
unsigned dir:1; /* 1 = IN(write), 0 = OUT(read) */
|
||||
};
|
||||
|
||||
struct r8a66597 {
|
||||
spinlock_t lock;
|
||||
void __iomem *reg;
|
||||
void __iomem *sudmac_reg;
|
||||
|
||||
#ifdef CONFIG_HAVE_CLK
|
||||
struct clk *clk;
|
||||
|
@ -94,6 +103,7 @@ struct r8a66597 {
|
|||
struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE];
|
||||
struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE];
|
||||
struct r8a66597_ep *epaddr2ep[16];
|
||||
struct r8a66597_dma dma;
|
||||
|
||||
struct timer_list timer;
|
||||
struct usb_request *ep0_req; /* for internal request */
|
||||
|
@ -251,7 +261,21 @@ static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
|
|||
return clock;
|
||||
}
|
||||
|
||||
static inline u32 r8a66597_sudmac_read(struct r8a66597 *r8a66597,
|
||||
unsigned long offset)
|
||||
{
|
||||
return ioread32(r8a66597->sudmac_reg + offset);
|
||||
}
|
||||
|
||||
static inline void r8a66597_sudmac_write(struct r8a66597 *r8a66597, u32 val,
|
||||
unsigned long offset)
|
||||
{
|
||||
iowrite32(val, r8a66597->sudmac_reg + offset);
|
||||
}
|
||||
|
||||
#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
|
||||
#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
|
||||
#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
|
||||
|
||||
#define enable_irq_ready(r8a66597, pipenum) \
|
||||
enable_pipe_irq(r8a66597, pipenum, BRDYENB)
|
||||
|
|
|
@ -48,6 +48,9 @@ struct r8a66597_platdata {
|
|||
|
||||
/* (external controller only) set one = WR0_N shorted to WR1_N */
|
||||
unsigned wr0_shorted_to_wr1:1;
|
||||
|
||||
/* set one = using SUDMAC */
|
||||
unsigned sudmac:1;
|
||||
};
|
||||
|
||||
/* Register definitions */
|
||||
|
@ -417,5 +420,62 @@ struct r8a66597_platdata {
|
|||
#define USBSPD 0x00C0
|
||||
#define RTPORT 0x0001
|
||||
|
||||
/* SUDMAC registers */
|
||||
#define CH0CFG 0x00
|
||||
#define CH1CFG 0x04
|
||||
#define CH0BA 0x10
|
||||
#define CH1BA 0x14
|
||||
#define CH0BBC 0x18
|
||||
#define CH1BBC 0x1C
|
||||
#define CH0CA 0x20
|
||||
#define CH1CA 0x24
|
||||
#define CH0CBC 0x28
|
||||
#define CH1CBC 0x2C
|
||||
#define CH0DEN 0x30
|
||||
#define CH1DEN 0x34
|
||||
#define DSTSCLR 0x38
|
||||
#define DBUFCTRL 0x3C
|
||||
#define DINTCTRL 0x40
|
||||
#define DINTSTS 0x44
|
||||
#define DINTSTSCLR 0x48
|
||||
#define CH0SHCTRL 0x50
|
||||
#define CH1SHCTRL 0x54
|
||||
|
||||
/* SUDMAC Configuration Registers */
|
||||
#define SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */
|
||||
#define RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */
|
||||
#define LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */
|
||||
|
||||
/* DMA Enable Registers */
|
||||
#define DEN 0x0001 /* b1: DMA Transfer Enable */
|
||||
|
||||
/* DMA Status Clear Register */
|
||||
#define CH1STCLR 0x0002 /* b2: Ch1 DMA Status Clear */
|
||||
#define CH0STCLR 0x0001 /* b1: Ch0 DMA Status Clear */
|
||||
|
||||
/* DMA Buffer Control Register */
|
||||
#define CH1BUFW 0x0200 /* b9: Ch1 DMA Buffer Data Transfer Enable */
|
||||
#define CH0BUFW 0x0100 /* b8: Ch0 DMA Buffer Data Transfer Enable */
|
||||
#define CH1BUFS 0x0002 /* b2: Ch1 DMA Buffer Data Status */
|
||||
#define CH0BUFS 0x0001 /* b1: Ch0 DMA Buffer Data Status */
|
||||
|
||||
/* DMA Interrupt Control Register */
|
||||
#define CH1ERRE 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Enable */
|
||||
#define CH0ERRE 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Enable */
|
||||
#define CH1ENDE 0x0002 /* b2: Ch1 DMA Transfer End Int Enable */
|
||||
#define CH0ENDE 0x0001 /* b1: Ch0 DMA Transfer End Int Enable */
|
||||
|
||||
/* DMA Interrupt Status Register */
|
||||
#define CH1ERRS 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Status */
|
||||
#define CH0ERRS 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Status */
|
||||
#define CH1ENDS 0x0002 /* b2: Ch1 DMA Transfer End Int Status */
|
||||
#define CH0ENDS 0x0001 /* b1: Ch0 DMA Transfer End Int Status */
|
||||
|
||||
/* DMA Interrupt Status Clear Register */
|
||||
#define CH1ERRC 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Stat Clear */
|
||||
#define CH0ERRC 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Stat Clear */
|
||||
#define CH1ENDC 0x0002 /* b2: Ch1 DMA Transfer End Int Stat Clear */
|
||||
#define CH0ENDC 0x0001 /* b1: Ch0 DMA Transfer End Int Stat Clear */
|
||||
|
||||
#endif /* __LINUX_USB_R8A66597_H */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче