usb: gadget: pch_udc: Fix disconnect issue
[linux-flexiantxendom0.git] / drivers / usb / gadget / pch_udc.c
index 0c8dd81..147ec4e 100644 (file)
@@ -1,18 +1,9 @@
 /*
- * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2 of the License.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/kernel.h>
 #define PCH_UDC_BRLEN          0x0F    /* Burst length */
 #define PCH_UDC_THLEN          0x1F    /* Threshold length */
 /* Value of EP Buffer Size */
-#define UDC_EP0IN_BUFF_SIZE    64
-#define UDC_EPIN_BUFF_SIZE     512
-#define UDC_EP0OUT_BUFF_SIZE   64
-#define UDC_EPOUT_BUFF_SIZE    512
+#define UDC_EP0IN_BUFF_SIZE    16
+#define UDC_EPIN_BUFF_SIZE     256
+#define UDC_EP0OUT_BUFF_SIZE   16
+#define UDC_EPOUT_BUFF_SIZE    256
 /* Value of EP maximum packet size */
 #define UDC_EP0IN_MAX_PKT_SIZE 64
 #define UDC_EP0OUT_MAX_PKT_SIZE        64
@@ -351,7 +342,7 @@ struct pch_udc_dev {
        struct pci_pool         *data_requests;
        struct pci_pool         *stp_requests;
        dma_addr_t                      dma_addr;
-       unsigned long                   ep0out_buf[64];
+       void                            *ep0out_buf;
        struct usb_ctrlrequest          setup_data;
        unsigned long                   phys_addr;
        void __iomem                    *base_addr;
@@ -361,11 +352,13 @@ struct pch_udc_dev {
 
 #define PCH_UDC_PCI_BAR                        1
 #define PCI_DEVICE_ID_INTEL_EG20T_UDC  0x8808
+#define PCI_VENDOR_ID_ROHM             0x10DB
+#define PCI_DEVICE_ID_ML7213_IOH_UDC   0x801D
+#define PCI_DEVICE_ID_ML7831_IOH_UDC   0x8808
 
 static const char      ep0_string[] = "ep0in";
 static DEFINE_SPINLOCK(udc_stall_spinlock);    /* stall spin lock */
 struct pch_udc_dev *pch_udc;           /* pointer to device object */
-
 static int speed_fs;
 module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
 MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
@@ -381,6 +374,8 @@ MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
  * @dma_mapped:                DMA memory mapped for request
  * @dma_done:          DMA completed for request
  * @chain_len:         chain length
+ * @buf:               Buffer memory for align adjustment
+ * @dma:               DMA memory for align adjustment
  */
 struct pch_udc_request {
        struct usb_request              req;
@@ -392,6 +387,8 @@ struct pch_udc_request {
                                        dma_mapped:1,
                                        dma_done:1;
        unsigned                        chain_len;
+       void                            *buf;
+       dma_addr_t                      dma;
 };
 
 static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg)
@@ -613,7 +610,7 @@ static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep,
 /**
  * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint
  * @ep:                Reference to structure of type pch_udc_ep_regs
- * @buf_size:  The buffer size
+ * @buf_size:  The buffer word size
  */
 static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,
                                                 u32 buf_size, u32 ep_in)
@@ -633,7 +630,7 @@ static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,
 /**
  * pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint
  * @ep:                Reference to structure of type pch_udc_ep_regs
- * @pkt_size:  The packet size
+ * @pkt_size:  The packet byte size
  */
 static void pch_udc_ep_set_maxpkt(struct pch_udc_ep *ep, u32 pkt_size)
 {
@@ -918,25 +915,10 @@ static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep)
  */
 static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir)
 {
-       unsigned int loopcnt = 0;
-       struct pch_udc_dev *dev = ep->dev;
-
        if (dir) {      /* IN ep */
                pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F);
                return;
        }
-
-       if (pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP)
-               return;
-       pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
-       /* Wait for RxFIFO Empty */
-       loopcnt = 10000;
-       while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) &&
-               --loopcnt)
-               udelay(5);
-       if (!loopcnt)
-               dev_err(&dev->pdev->dev, "RxFIFO not Empty\n");
-       pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_MRXFLUSH);
 }
 
 /**
@@ -957,7 +939,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
        else
                buff_size = UDC_EPOUT_BUFF_SIZE;
        pch_udc_ep_set_bufsz(ep, buff_size, ep->in);
-       pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize));
+       pch_udc_ep_set_maxpkt(ep, usb_endpoint_maxp(desc));
        pch_udc_ep_set_nak(ep);
        pch_udc_ep_fifo_flush(ep, ep->in);
        /* Configure the endpoint */
@@ -967,7 +949,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
              (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) |
              (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) |
              (cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) |
-             le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT;
+             usb_endpoint_maxp(desc) << UDC_CSR_NE_MAX_PKT_SHIFT;
 
        if (ep->in)
                pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num));
@@ -1186,6 +1168,9 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
        return -EOPNOTSUPP;
 }
 
+static int pch_udc_start(struct usb_gadget_driver *driver,
+       int (*bind)(struct usb_gadget *));
+static int pch_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops pch_udc_ops = {
        .get_frame = pch_udc_pcd_get_frame,
        .wakeup = pch_udc_pcd_wakeup,
@@ -1193,6 +1178,8 @@ static const struct usb_gadget_ops pch_udc_ops = {
        .pullup = pch_udc_pcd_pullup,
        .vbus_session = pch_udc_pcd_vbus_session,
        .vbus_draw = pch_udc_pcd_vbus_draw,
+       .start  = pch_udc_start,
+       .stop   = pch_udc_stop,
 };
 
 /**
@@ -1218,14 +1205,31 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
 
        dev = ep->dev;
        if (req->dma_mapped) {
-               if (ep->in)
-                       pci_unmap_single(dev->pdev, req->req.dma,
-                                        req->req.length, PCI_DMA_TODEVICE);
-               else
-                       pci_unmap_single(dev->pdev, req->req.dma,
-                                        req->req.length, PCI_DMA_FROMDEVICE);
+               if (req->dma == DMA_ADDR_INVALID) {
+                       if (ep->in)
+                               dma_unmap_single(&dev->pdev->dev, req->req.dma,
+                                                req->req.length,
+                                                DMA_TO_DEVICE);
+                       else
+                               dma_unmap_single(&dev->pdev->dev, req->req.dma,
+                                                req->req.length,
+                                                DMA_FROM_DEVICE);
+                       req->req.dma = DMA_ADDR_INVALID;
+               } else {
+                       if (ep->in)
+                               dma_unmap_single(&dev->pdev->dev, req->dma,
+                                                req->req.length,
+                                                DMA_TO_DEVICE);
+                       else {
+                               dma_unmap_single(&dev->pdev->dev, req->dma,
+                                                req->req.length,
+                                                DMA_FROM_DEVICE);
+                               memcpy(req->req.buf, req->buf, req->req.length);
+                       }
+                       kfree(req->buf);
+                       req->dma = DMA_ADDR_INVALID;
+               }
                req->dma_mapped = 0;
-               req->req.dma = DMA_ADDR_INVALID;
        }
        ep->halted = 1;
        spin_unlock(&dev->lock);
@@ -1266,12 +1270,18 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
        struct pch_udc_data_dma_desc *td = req->td_data;
        unsigned i = req->chain_len;
 
+       dma_addr_t addr2;
+       dma_addr_t addr = (dma_addr_t)td->next;
+       td->next = 0x00;
        for (; i > 1; --i) {
-               dma_addr_t addr = (dma_addr_t)td->next;
                /* do not free first desc., will be done by free for request */
                td = phys_to_virt(addr);
+               addr2 = (dma_addr_t)td->next;
                pci_pool_free(dev->data_requests, td, addr);
+               td->next = 0x00;
+               addr = addr2;
        }
+       req->chain_len = 1;
 }
 
 /**
@@ -1299,23 +1309,23 @@ static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,
        if (req->chain_len > 1)
                pch_udc_free_dma_chain(ep->dev, req);
 
-       for (; ; bytes -= buf_len, ++len) {
-               if (ep->in)
-                       td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes);
-               else
-                       td->status = PCH_UDC_BS_HST_BSY;
+       if (req->dma == DMA_ADDR_INVALID)
+               td->dataptr = req->req.dma;
+       else
+               td->dataptr = req->dma;
 
+       td->status = PCH_UDC_BS_HST_BSY;
+       for (; ; bytes -= buf_len, ++len) {
+               td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes);
                if (bytes <= buf_len)
                        break;
-
                last = td;
                td = pci_pool_alloc(ep->dev->data_requests, gfp_flags,
                                    &dma_addr);
                if (!td)
                        goto nomem;
-
                i += buf_len;
-               td->dataptr = req->req.dma + i;
+               td->dataptr = req->td_data->dataptr + i;
                last->next = dma_addr;
        }
 
@@ -1350,28 +1360,15 @@ static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req,
 {
        int     retval;
 
-       req->td_data->dataptr = req->req.dma;
-       req->td_data->status |= PCH_UDC_DMA_LAST;
        /* Allocate and create a DMA chain */
        retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
        if (retval) {
-               pr_err("%s: could not create DMA chain: %d\n",
-                      __func__, retval);
+               pr_err("%s: could not create DMA chain:%d\n", __func__, retval);
                return retval;
        }
-       if (!ep->in)
-               return 0;
-       if (req->req.length <= ep->ep.maxpacket)
-               req->td_data->status = PCH_UDC_DMA_LAST | PCH_UDC_BS_HST_BSY |
-                                      req->req.length;
-       /* if bytes < max packet then tx bytes must
-        * be written in packet per buffer mode
-        */
-       if ((req->req.length < ep->ep.maxpacket) || !ep->num)
+       if (ep->in)
                req->td_data->status = (req->td_data->status &
-                                       ~PCH_UDC_RXTX_BYTES) | req->req.length;
-       req->td_data->status = (req->td_data->status &
-                               ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_BSY;
+                               ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_RDY;
        return 0;
 }
 
@@ -1414,7 +1411,6 @@ static void pch_udc_start_rxrequest(struct pch_udc_ep *ep,
 
        pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
        td_data = req->td_data;
-       ep->td_data = req->td_data;
        /* Set the status bits for all descriptors */
        while (1) {
                td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) |
@@ -1462,7 +1458,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
        ep->desc = desc;
        ep->halted = 0;
        pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
-       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+       ep->ep.maxpacket = usb_endpoint_maxp(desc);
        pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
        spin_unlock_irqrestore(&dev->lock, iflags);
        return 0;
@@ -1528,6 +1524,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
        if (!req)
                return NULL;
        req->req.dma = DMA_ADDR_INVALID;
+       req->dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD(&req->queue);
        if (!ep->dev->dma_addr)
                return &req->req;
@@ -1608,20 +1605,43 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
                return -EINVAL;
        if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
                return -ESHUTDOWN;
-       spin_lock_irqsave(&ep->dev->lock, iflags);
+       spin_lock_irqsave(&dev->lock, iflags);
        /* map the buffer for dma */
        if (usbreq->length &&
            ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
-               if (ep->in)
-                       usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
-                                       usbreq->length, PCI_DMA_TODEVICE);
-               else
-                       usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
-                                       usbreq->length, PCI_DMA_FROMDEVICE);
+               if (!((unsigned long)(usbreq->buf) & 0x03)) {
+                       if (ep->in)
+                               usbreq->dma = dma_map_single(&dev->pdev->dev,
+                                                            usbreq->buf,
+                                                            usbreq->length,
+                                                            DMA_TO_DEVICE);
+                       else
+                               usbreq->dma = dma_map_single(&dev->pdev->dev,
+                                                            usbreq->buf,
+                                                            usbreq->length,
+                                                            DMA_FROM_DEVICE);
+               } else {
+                       req->buf = kzalloc(usbreq->length, GFP_ATOMIC);
+                       if (!req->buf) {
+                               retval = -ENOMEM;
+                               goto probe_end;
+                       }
+                       if (ep->in) {
+                               memcpy(req->buf, usbreq->buf, usbreq->length);
+                               req->dma = dma_map_single(&dev->pdev->dev,
+                                                         req->buf,
+                                                         usbreq->length,
+                                                         DMA_TO_DEVICE);
+                       } else
+                               req->dma = dma_map_single(&dev->pdev->dev,
+                                                         req->buf,
+                                                         usbreq->length,
+                                                         DMA_FROM_DEVICE);
+               }
                req->dma_mapped = 1;
        }
        if (usbreq->length > 0) {
-               retval = prepare_dma(ep, req, gfp);
+               retval = prepare_dma(ep, req, GFP_ATOMIC);
                if (retval)
                        goto probe_end;
        }
@@ -1646,7 +1666,6 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
                        pch_udc_wait_ep_stall(ep);
                        pch_udc_ep_clear_nak(ep);
                        pch_udc_enable_ep_interrupts(ep->dev, (1 << ep->num));
-                       pch_udc_set_dma(dev, DMA_DIR_TX);
                }
        }
        /* Now add this request to the ep's pending requests */
@@ -1916,31 +1935,46 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
        struct pch_udc_request *req;
        struct pch_udc_dev *dev = ep->dev;
        unsigned int count;
+       struct pch_udc_data_dma_desc *td;
+       dma_addr_t addr;
 
        if (list_empty(&ep->queue))
                return;
-
        /* next request */
        req = list_entry(ep->queue.next, struct pch_udc_request, queue);
-       if ((req->td_data_last->status & PCH_UDC_BUFF_STS) !=
-           PCH_UDC_BS_DMA_DONE)
-               return;
        pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
-       if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
-           PCH_UDC_RTS_SUCC) {
-               dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) "
-                       "epstatus=0x%08x\n",
-                       (req->td_data_last->status & PCH_UDC_RXTX_STS),
-                       (int)(ep->epsts));
-               return;
-       }
-       count = req->td_data_last->status & PCH_UDC_RXTX_BYTES;
+       pch_udc_ep_set_ddptr(ep, 0);
+       if ((req->td_data_last->status & PCH_UDC_BUFF_STS) ==
+           PCH_UDC_BS_DMA_DONE)
+               td = req->td_data_last;
+       else
+               td = req->td_data;
 
+       while (1) {
+               if ((td->status & PCH_UDC_RXTX_STS) != PCH_UDC_RTS_SUCC) {
+                       dev_err(&dev->pdev->dev, "Invalid RXTX status=0x%08x "
+                               "epstatus=0x%08x\n",
+                               (req->td_data->status & PCH_UDC_RXTX_STS),
+                               (int)(ep->epsts));
+                       return;
+               }
+               if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE)
+                       if (td->status | PCH_UDC_DMA_LAST) {
+                               count = td->status & PCH_UDC_RXTX_BYTES;
+                               break;
+                       }
+               if (td == req->td_data_last) {
+                       dev_err(&dev->pdev->dev, "Not complete RX descriptor");
+                       return;
+               }
+               addr = (dma_addr_t)td->next;
+               td = phys_to_virt(addr);
+       }
        /* on 64k packets the RXBYTES field is zero */
        if (!count && (req->req.length == UDC_DMA_MAXPACKET))
                count = UDC_DMA_MAXPACKET;
        req->td_data->status |= PCH_UDC_DMA_LAST;
-       req->td_data_last->status |= PCH_UDC_BS_HST_BSY;
+       td->status |= PCH_UDC_BS_HST_BSY;
 
        req->dma_going = 0;
        req->req.actual = count;
@@ -1963,7 +1997,7 @@ static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
        u32     epsts;
        struct pch_udc_ep       *ep;
 
-       ep = &dev->ep[2*ep_num];
+       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2008,7 +2042,7 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
        struct pch_udc_ep               *ep;
        struct pch_udc_request          *req = NULL;
 
-       ep = &dev->ep[2*ep_num + 1];
+       ep = &dev->ep[UDC_EPOUT_IDX(ep_num)];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2025,10 +2059,11 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
        }
        if (epsts & UDC_EPSTS_HE)
                return;
-       if (epsts & UDC_EPSTS_RSS)
+       if (epsts & UDC_EPSTS_RSS) {
                pch_udc_ep_set_stall(ep);
                pch_udc_enable_ep_interrupts(ep->dev,
                                             PCH_UDC_EPINT(ep->in, ep->num));
+       }
        if (epsts & UDC_EPSTS_RCS) {
                if (!dev->prot_stall) {
                        pch_udc_ep_clear_stall(ep);
@@ -2060,8 +2095,10 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
 {
        u32     epsts;
        struct pch_udc_ep       *ep;
+       struct pch_udc_ep       *ep_out;
 
        ep = &dev->ep[UDC_EP0IN_IDX];
+       ep_out = &dev->ep[UDC_EP0OUT_IDX];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2073,8 +2110,16 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
                return;
        if (epsts & UDC_EPSTS_HE)
                return;
-       if ((epsts & UDC_EPSTS_TDC) && (!dev->stall))
+       if ((epsts & UDC_EPSTS_TDC) && (!dev->stall)) {
                pch_udc_complete_transfer(ep);
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
+               ep_out->td_data->status = (ep_out->td_data->status &
+                                       ~PCH_UDC_BUFF_STS) |
+                                       PCH_UDC_BS_HST_RDY;
+               pch_udc_ep_clear_nak(ep_out);
+               pch_udc_set_dma(dev, DMA_DIR_RX);
+               pch_udc_ep_set_rrdy(ep_out);
+       }
        /* On IN interrupt, provide data if we have any */
        if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_TDC) &&
             !(epsts & UDC_EPSTS_TXEMPTY))
@@ -2102,11 +2147,9 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                dev->stall = 0;
                dev->ep[UDC_EP0IN_IDX].halted = 0;
                dev->ep[UDC_EP0OUT_IDX].halted = 0;
-               /* In data not ready */
-               pch_udc_ep_set_nak(&(dev->ep[UDC_EP0IN_IDX]));
                dev->setup_data = ep->td_stp->request;
                pch_udc_init_setup_buff(ep->td_stp);
-               pch_udc_clear_dma(dev, DMA_DIR_TX);
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
                pch_udc_ep_fifo_flush(&(dev->ep[UDC_EP0IN_IDX]),
                                      dev->ep[UDC_EP0IN_IDX].in);
                if ((dev->setup_data.bRequestType & USB_DIR_IN))
@@ -2122,14 +2165,23 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                setup_supported = dev->driver->setup(&dev->gadget,
                                                     &dev->setup_data);
                spin_lock(&dev->lock);
+
+               if (dev->setup_data.bRequestType & USB_DIR_IN) {
+                       ep->td_data->status = (ep->td_data->status &
+                                               ~PCH_UDC_BUFF_STS) |
+                                               PCH_UDC_BS_HST_RDY;
+                       pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
+               }
                /* ep0 in returns data on IN phase */
                if (setup_supported >= 0 && setup_supported <
                                            UDC_EP0IN_MAX_PKT_SIZE) {
                        pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX]));
                        /* Gadget would have queued a request when
                         * we called the setup */
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
-                       pch_udc_ep_clear_nak(ep);
+                       if (!(dev->setup_data.bRequestType & USB_DIR_IN)) {
+                               pch_udc_set_dma(dev, DMA_DIR_RX);
+                               pch_udc_ep_clear_nak(ep);
+                       }
                } else if (setup_supported < 0) {
                        /* if unsupported request, then stall */
                        pch_udc_ep_set_stall(&(dev->ep[UDC_EP0IN_IDX]));
@@ -2142,22 +2194,13 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                }
        } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
                     UDC_EPSTS_OUT_DATA) && !dev->stall) {
-               if (list_empty(&ep->queue)) {
-                       dev_err(&dev->pdev->dev, "%s: No request\n", __func__);
-                       ep->td_data->status = (ep->td_data->status &
-                                              ~PCH_UDC_BUFF_STS) |
-                                              PCH_UDC_BS_HST_RDY;
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
-               } else {
-                       /* control write */
-                       /* next function will pickuo an clear the status */
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
+               pch_udc_ep_set_ddptr(ep, 0);
+               if (!list_empty(&ep->queue)) {
                        ep->epsts = stat;
-
-                       pch_udc_svc_data_out(dev, 0);
-                       /* re-program desc. pointer for possible ZLPs */
-                       pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
+                       pch_udc_svc_data_out(dev, PCH_UDC_EP0);
                }
+               pch_udc_set_dma(dev, DMA_DIR_RX);
        }
        pch_udc_ep_set_rrdy(ep);
 }
@@ -2174,7 +2217,7 @@ static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
        struct pch_udc_ep       *ep;
        struct pch_udc_request *req;
 
-       ep = &dev->ep[2*ep_num];
+       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
        if (!list_empty(&ep->queue)) {
                req = list_entry(ep->queue.next, struct pch_udc_request, queue);
                pch_udc_enable_ep_interrupts(ep->dev,
@@ -2196,13 +2239,13 @@ static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
        for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
                /* IN */
                if (ep_intr & (0x1 << i)) {
-                       ep = &dev->ep[2*i];
+                       ep = &dev->ep[UDC_EPIN_IDX(i)];
                        ep->epsts = pch_udc_read_ep_status(ep);
                        pch_udc_clear_ep_status(ep, ep->epsts);
                }
                /* OUT */
                if (ep_intr & (0x10000 << i)) {
-                       ep = &dev->ep[2*i+1];
+                       ep = &dev->ep[UDC_EPOUT_IDX(i)];
                        ep->epsts = pch_udc_read_ep_status(ep);
                        pch_udc_clear_ep_status(ep, ep->epsts);
                }
@@ -2292,8 +2335,11 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
                /* Complete request queue */
                empty_req_queue(ep);
        }
-       if (dev->driver && dev->driver->disconnect)
+       if (dev->driver && dev->driver->disconnect) {
+               spin_unlock(&dev->lock);
                dev->driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+       }
 }
 
 /**
@@ -2563,9 +2609,6 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
        dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
        dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
 
-       dev->dma_addr = pci_map_single(dev->pdev, dev->ep0out_buf, 256,
-                                 PCI_DMA_FROMDEVICE);
-
        /* remove ep0 in and out from the list.  They have own pointer */
        list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list);
        list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list);
@@ -2637,10 +2680,17 @@ static int init_dma_pools(struct pch_udc_dev *dev)
        dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0;
        dev->ep[UDC_EP0IN_IDX].td_data = NULL;
        dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
+
+       dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL);
+       if (!dev->ep0out_buf)
+               return -ENOMEM;
+       dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf,
+                                      UDC_EP0OUT_BUFF_SIZE * 4,
+                                      DMA_FROM_DEVICE);
        return 0;
 }
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pch_udc_start(struct usb_gadget_driver *driver,
        int (*bind)(struct usb_gadget *))
 {
        struct pch_udc_dev      *dev = pch_udc;
@@ -2683,9 +2733,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
        dev->connected = 1;
        return 0;
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pch_udc_stop(struct usb_gadget_driver *driver)
 {
        struct pch_udc_dev      *dev = pch_udc;
 
@@ -2700,7 +2749,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
        pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
 
-       /* Assues that there are no pending requets with this driver */
+       /* Assures that there are no pending requests with this driver */
+       driver->disconnect(&dev->gadget);
        driver->unbind(&dev->gadget);
        dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
@@ -2710,7 +2760,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        pch_udc_set_disconnect(dev);
        return 0;
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 static void pch_udc_shutdown(struct pci_dev *pdev)
 {
@@ -2727,6 +2776,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
 {
        struct pch_udc_dev      *dev = pci_get_drvdata(pdev);
 
+       usb_del_gadget_udc(&dev->gadget);
+
        /* gadget driver must not be registered */
        if (dev->driver)
                dev_err(&pdev->dev,
@@ -2750,6 +2801,11 @@ static void pch_udc_remove(struct pci_dev *pdev)
                pci_pool_destroy(dev->stp_requests);
        }
 
+       if (dev->dma_addr)
+               dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
+                                UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
+       kfree(dev->ep0out_buf);
+
        pch_udc_exit(dev);
 
        if (dev->irq_registered)
@@ -2792,11 +2848,7 @@ static int pch_udc_resume(struct pci_dev *pdev)
        int ret;
 
        pci_set_power_state(pdev, PCI_D0);
-       ret = pci_restore_state(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: pci_restore_state failed\n", __func__);
-               return ret;
-       }
+       pci_restore_state(pdev);
        ret = pci_enable_device(pdev);
        if (ret) {
                dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
@@ -2901,6 +2953,9 @@ static int pch_udc_probe(struct pci_dev *pdev,
 
        /* Put the device in disconnected state till a driver is bound */
        pch_udc_set_disconnect(dev);
+       retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+       if (retval)
+               goto finished;
        return 0;
 
 finished:
@@ -2914,6 +2969,16 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
                .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
                .class_mask = 0xffffffff,
        },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7213_IOH_UDC),
+               .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask = 0xffffffff,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7831_IOH_UDC),
+               .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask = 0xffffffff,
+       },
        { 0 },
 };
 
@@ -2943,5 +3008,5 @@ static void __exit pch_udc_pci_exit(void)
 module_exit(pch_udc_pci_exit);
 
 MODULE_DESCRIPTION("Intel EG20T USB Device Controller");
-MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>");
+MODULE_AUTHOR("LAPIS Semiconductor, <tomoya-linux@dsn.lapis-semi.com>");
 MODULE_LICENSE("GPL");