usb: gadget: pch_udc: Fix usb/gadget/pch_udc: Fix ether gadget connect/disconnect...
[linux-flexiantxendom0.git] / drivers / usb / gadget / pch_udc.c
index 4a52569..4d1e91e 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
@@ -320,6 +311,7 @@ struct pch_udc_ep {
  * @registered:                driver regsitered with system
  * @suspended:         driver in suspended state
  * @connected:         gadget driver associated
+ * @vbus_session:      required vbus_session state
  * @set_cfg_not_acked: pending acknowledgement 4 setup
  * @waiting_zlp_ack:   pending acknowledgement 4 ZLP
  * @data_requests:     DMA pool for data requests
@@ -337,7 +329,7 @@ struct pch_udc_dev {
        struct usb_gadget_driver        *driver;
        struct pci_dev                  *pdev;
        struct pch_udc_ep               ep[PCH_UDC_EP_NUM];
-       spinlock_t                      lock;
+       spinlock_t                      lock; /* protects all state */
        unsigned        active:1,
                        stall:1,
                        prot_stall:1,
@@ -346,12 +338,13 @@ struct pch_udc_dev {
                        registered:1,
                        suspended:1,
                        connected:1,
+                       vbus_session:1,
                        set_cfg_not_acked:1,
                        waiting_zlp_ack:1;
        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 +354,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 +376,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 +389,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)
@@ -557,6 +556,31 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
 }
 
 /**
+ * pch_udc_reconnect() - This API initializes usb device controller,
+ *                                             and clear the disconnect status.
+ * @dev:               Reference to pch_udc_regs structure
+ */
+static void pch_udc_init(struct pch_udc_dev *dev);
+static void pch_udc_reconnect(struct pch_udc_dev *dev)
+{
+       pch_udc_init(dev);
+
+       /* enable device interrupts */
+       /* pch_udc_enable_interrupts() */
+       pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
+                       UDC_DEVINT_UR | UDC_DEVINT_US |
+                       UDC_DEVINT_ENUM |
+                       UDC_DEVINT_SI | UDC_DEVINT_SC);
+
+       /* Clear the disconnect */
+       pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+       pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+       mdelay(1);
+       /* Resume USB signalling */
+       pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
  * pch_udc_vbus_session() - set or clearr the disconnect status.
  * @dev:       Reference to pch_udc_regs structure
  * @is_active: Parameter specifying the action
@@ -566,10 +590,18 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
 static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
                                          int is_active)
 {
-       if (is_active)
-               pch_udc_clear_disconnect(dev);
-       else
+       if (is_active) {
+               pch_udc_reconnect(dev);
+               dev->vbus_session = 1;
+       } else {
+               if (dev->driver && dev->driver->disconnect) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->disconnect(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
                pch_udc_set_disconnect(dev);
+               dev->vbus_session = 0;
+       }
 }
 
 /**
@@ -613,7 +645,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 +665,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 +950,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 +974,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 +984,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));
@@ -1144,7 +1161,17 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
        if (!gadget)
                return -EINVAL;
        dev = container_of(gadget, struct pch_udc_dev, gadget);
-       pch_udc_vbus_session(dev, is_on);
+       if (is_on) {
+               pch_udc_reconnect(dev);
+       } else {
+               if (dev->driver && dev->driver->disconnect) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->disconnect(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
+               pch_udc_set_disconnect(dev);
+       }
+
        return 0;
 }
 
@@ -1186,6 +1213,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 +1223,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 +1250,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 +1315,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 +1354,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 +1405,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 +1456,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 +1503,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 +1569,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 +1650,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 +1711,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 +1980,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 +2042,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;
 
@@ -1980,7 +2059,7 @@ static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
                pch_udc_enable_ep_interrupts(ep->dev,
                                             PCH_UDC_EPINT(ep->in, ep->num));
        }
-       if (epsts & UDC_EPSTS_RCS)
+       if (epsts & UDC_EPSTS_RCS) {
                if (!dev->prot_stall) {
                        pch_udc_ep_clear_stall(ep);
                } else {
@@ -1988,6 +2067,7 @@ static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
                        pch_udc_enable_ep_interrupts(ep->dev,
                                                PCH_UDC_EPINT(ep->in, ep->num));
                }
+       }
        if (epsts & UDC_EPSTS_TDC)
                pch_udc_complete_transfer(ep);
        /* On IN interrupt, provide data if we have any */
@@ -2007,7 +2087,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;
 
@@ -2024,11 +2104,12 @@ 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 (epsts & UDC_EPSTS_RCS) {
                if (!dev->prot_stall) {
                        pch_udc_ep_clear_stall(ep);
                } else {
@@ -2036,6 +2117,7 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
                        pch_udc_enable_ep_interrupts(ep->dev,
                                                PCH_UDC_EPINT(ep->in, ep->num));
                }
+       }
        if (((epsts & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
            UDC_EPSTS_OUT_DATA) {
                if (ep->dev->prot_stall == 1) {
@@ -2058,8 +2140,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;
 
@@ -2071,8 +2155,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))
@@ -2100,11 +2192,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))
@@ -2120,14 +2210,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]));
@@ -2140,19 +2239,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 */
-                       pch_udc_svc_data_out(dev, UDC_EP0OUT_IDX);
-                       /* 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_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, PCH_UDC_EP0);
                }
+               pch_udc_set_dma(dev, DMA_DIR_RX);
        }
        pch_udc_ep_set_rrdy(ep);
 }
@@ -2169,7 +2262,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,
@@ -2191,13 +2284,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);
                }
@@ -2287,8 +2380,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);
+       }
 }
 
 /**
@@ -2424,8 +2520,24 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
        if (dev_intr & UDC_DEVINT_SC)
                pch_udc_svc_cfg_interrupt(dev);
        /* USB Suspend interrupt */
-       if (dev_intr & UDC_DEVINT_US)
+       if (dev_intr & UDC_DEVINT_US) {
+               if (dev->driver
+                       && dev->driver->suspend) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->suspend(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
+
+               if (dev->vbus_session == 0) {
+                       if (dev->driver && dev->driver->disconnect) {
+                               spin_unlock(&dev->lock);
+                               dev->driver->disconnect(&dev->gadget);
+                               spin_lock(&dev->lock);
+                       }
+                       pch_udc_reconnect(dev);
+               }
                dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
+       }
        /* Clear the SOF interrupt, if enabled */
        if (dev_intr & UDC_DEVINT_SOF)
                dev_dbg(&dev->pdev->dev, "SOF\n");
@@ -2451,6 +2563,14 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev)
        dev_intr = pch_udc_read_device_interrupts(dev);
        ep_intr = pch_udc_read_ep_interrupts(dev);
 
+       /* For a hot plug, this find that the controller is hung up. */
+       if (dev_intr == ep_intr)
+               if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
+                       dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
+                       /* The controller is reset */
+                       pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+                       return IRQ_HANDLED;
+               }
        if (dev_intr)
                /* Clear device interrupts */
                pch_udc_write_device_interrupts(dev, dev_intr);
@@ -2558,9 +2678,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);
@@ -2632,15 +2749,23 @@ 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_register_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;
        int                     retval;
 
-       if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !driver->bind ||
+       if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind ||
            !driver->setup || !driver->unbind || !driver->disconnect) {
                dev_err(&dev->pdev->dev,
                        "%s: invalid driver parameter\n", __func__);
@@ -2659,7 +2784,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        dev->gadget.dev.driver = &driver->driver;
 
        /* Invoke the bind routine of the gadget driver */
-       retval = driver->bind(&dev->gadget);
+       retval = bind(&dev->gadget);
 
        if (retval) {
                dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n",
@@ -2677,9 +2802,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        dev->connected = 1;
        return 0;
 }
-EXPORT_SYMBOL(usb_gadget_register_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;
 
@@ -2694,7 +2818,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;
@@ -2704,7 +2829,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)
 {
@@ -2721,6 +2845,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,
@@ -2744,6 +2870,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)
@@ -2786,11 +2917,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__);
@@ -2857,8 +2984,10 @@ static int pch_udc_probe(struct pci_dev *pdev,
        }
        pch_udc = dev;
        /* initialize the hardware */
-       if (pch_udc_pcd_init(dev))
+       if (pch_udc_pcd_init(dev)) {
+               retval = -ENODEV;
                goto finished;
+       }
        if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
                        dev)) {
                dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
@@ -2895,6 +3024,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:
@@ -2902,12 +3034,22 @@ finished:
        return retval;
 }
 
-static const struct pci_device_id pch_udc_pcidev_id[] = {
+static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
        {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),
                .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 },
 };
 
@@ -2937,5 +3079,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");