usb: gadget: r8a66597-udc: add support for SUDMAC
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Fri, 30 Sep 2011 11:07:38 +0000 (20:07 +0900)
committerFelipe Balbi <balbi@ti.com>
Thu, 13 Oct 2011 17:38:39 +0000 (20:38 +0300)
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>
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/r8a66597-udc.h
include/linux/usb/r8a66597.h

index 34abb12..035879b 100644 (file)
 #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);
index 832ee59..8e3de61 100644 (file)
@@ -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)
index b6b8660..55805f9 100644 (file)
@@ -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 */