OSDN Git Service

Merge tag 'usb-for-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
[android-x86/kernel.git] / drivers / usb / dwc2 / gadget.c
index 6d76e28..6a30887 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/phy.h>
 #include <linux/platform_data/s3c-hsotg.h>
+#include <linux/uaccess.h>
 
 #include "core.h"
 #include "hw.h"
@@ -177,6 +178,10 @@ static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
        int timeout;
        u32 val;
 
+       /* Reset fifo map if not correctly cleared during previous session */
+       WARN_ON(hsotg->fifo_map);
+       hsotg->fifo_map = 0;
+
        /* set RX/NPTX FIFO sizes */
        writel(hsotg->g_rx_fifo_sz, hsotg->regs + GRXFSIZ);
        writel((hsotg->g_rx_fifo_sz << FIFOSIZE_STARTADDR_SHIFT) |
@@ -230,6 +235,7 @@ static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
                        dev_err(hsotg->dev,
                                "%s: timeout flushing fifos (GRSTCTL=%08x)\n",
                                __func__, val);
+                       break;
                }
 
                udelay(1);
@@ -560,11 +566,6 @@ static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
        length = ureq->length - ureq->actual;
        dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
                ureq->length, ureq->actual);
-       if (0)
-               dev_dbg(hsotg->dev,
-                       "REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n",
-                       ureq->buf, length, &ureq->dma,
-                       ureq->no_interrupt, ureq->zero, ureq->short_not_ok);
 
        maxreq = get_ep_limit(hs_ep);
        if (length > maxreq) {
@@ -606,7 +607,7 @@ static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
                /* Test if zlp is actually required. */
                if ((ureq->length >= hs_ep->ep.maxpacket) &&
                                        !(ureq->length % hs_ep->ep.maxpacket))
-                       hs_ep->sent_zlp = 1;
+                       hs_ep->send_zlp = 1;
        }
 
        epsize |= DXEPTSIZ_PKTCNT(packets);
@@ -725,6 +726,59 @@ dma_error:
        return -EIO;
 }
 
+static int s3c_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg,
+       struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req)
+{
+       void *req_buf = hs_req->req.buf;
+
+       /* If dma is not being used or buffer is aligned */
+       if (!using_dma(hsotg) || !((long)req_buf & 3))
+               return 0;
+
+       WARN_ON(hs_req->saved_req_buf);
+
+       dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__,
+                       hs_ep->ep.name, req_buf, hs_req->req.length);
+
+       hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC);
+       if (!hs_req->req.buf) {
+               hs_req->req.buf = req_buf;
+               dev_err(hsotg->dev,
+                       "%s: unable to allocate memory for bounce buffer\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       /* Save actual buffer */
+       hs_req->saved_req_buf = req_buf;
+
+       if (hs_ep->dir_in)
+               memcpy(hs_req->req.buf, req_buf, hs_req->req.length);
+       return 0;
+}
+
+static void s3c_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg,
+       struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req)
+{
+       /* If dma is not being used or buffer was aligned */
+       if (!using_dma(hsotg) || !hs_req->saved_req_buf)
+               return;
+
+       dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__,
+               hs_ep->ep.name, hs_req->req.status, hs_req->req.actual);
+
+       /* Copy data from bounce buffer on successful out transfer */
+       if (!hs_ep->dir_in && !hs_req->req.status)
+               memcpy(hs_req->saved_req_buf, hs_req->req.buf,
+                                                       hs_req->req.actual);
+
+       /* Free bounce buffer */
+       kfree(hs_req->req.buf);
+
+       hs_req->req.buf = hs_req->saved_req_buf;
+       hs_req->saved_req_buf = NULL;
+}
+
 static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
                              gfp_t gfp_flags)
 {
@@ -732,6 +786,7 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
        struct s3c_hsotg_ep *hs_ep = our_ep(ep);
        struct dwc2_hsotg *hs = hs_ep->parent;
        bool first;
+       int ret;
 
        dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
                ep->name, req, req->length, req->buf, req->no_interrupt,
@@ -742,9 +797,13 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
        req->actual = 0;
        req->status = -EINPROGRESS;
 
+       ret = s3c_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req);
+       if (ret)
+               return ret;
+
        /* if we're using DMA, sync the buffers as necessary */
        if (using_dma(hs)) {
-               int ret = s3c_hsotg_map_dma(hs, hs_ep, req);
+               ret = s3c_hsotg_map_dma(hs, hs_ep, req);
                if (ret)
                        return ret;
        }
@@ -830,6 +889,32 @@ static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
 }
 
 /**
+ * s3c_hsotg_set_test_mode - Enable usb Test Modes
+ * @hsotg: The driver state.
+ * @testmode: requested usb test mode
+ * Enable usb Test Mode requested by the Host.
+ */
+static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
+{
+       int dctl = readl(hsotg->regs + DCTL);
+
+       dctl &= ~DCTL_TSTCTL_MASK;
+       switch (testmode) {
+       case TEST_J:
+       case TEST_K:
+       case TEST_SE0_NAK:
+       case TEST_PACKET:
+       case TEST_FORCE_EN:
+               dctl |= testmode << DCTL_TSTCTL_SHIFT;
+               break;
+       default:
+               return -EINVAL;
+       }
+       writel(dctl, hsotg->regs + DCTL);
+       return 0;
+}
+
+/**
  * s3c_hsotg_send_reply - send reply to control request
  * @hsotg: The device state
  * @ep: Endpoint 0
@@ -949,7 +1034,7 @@ static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
 }
 
 /**
- * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE
+ * s3c_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE
  * @hsotg: The device state
  * @ctrl: USB control request
  */
@@ -963,19 +1048,48 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
        struct s3c_hsotg_ep *ep;
        int ret;
        bool halted;
+       u32 recip;
+       u32 wValue;
+       u32 wIndex;
 
        dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
                __func__, set ? "SET" : "CLEAR");
 
-       if (ctrl->bRequestType == USB_RECIP_ENDPOINT) {
-               ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
+       wValue = le16_to_cpu(ctrl->wValue);
+       wIndex = le16_to_cpu(ctrl->wIndex);
+       recip = ctrl->bRequestType & USB_RECIP_MASK;
+
+       switch (recip) {
+       case USB_RECIP_DEVICE:
+               switch (wValue) {
+               case USB_DEVICE_TEST_MODE:
+                       if ((wIndex & 0xff) != 0)
+                               return -EINVAL;
+                       if (!set)
+                               return -EINVAL;
+
+                       hsotg->test_mode = wIndex >> 8;
+                       ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
+                       if (ret) {
+                               dev_err(hsotg->dev,
+                                       "%s: failed to send reply\n", __func__);
+                               return ret;
+                       }
+                       break;
+               default:
+                       return -ENOENT;
+               }
+               break;
+
+       case USB_RECIP_ENDPOINT:
+               ep = ep_from_windex(hsotg, wIndex);
                if (!ep) {
                        dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
-                               __func__, le16_to_cpu(ctrl->wIndex));
+                               __func__, wIndex);
                        return -ENOENT;
                }
 
-               switch (le16_to_cpu(ctrl->wValue)) {
+               switch (wValue) {
                case USB_ENDPOINT_HALT:
                        halted = ep->halted;
 
@@ -1002,16 +1116,22 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
                                        hs_req = ep->req;
                                        ep->req = NULL;
                                        list_del_init(&hs_req->queue);
-                                       usb_gadget_giveback_request(&ep->ep,
-                                                                   &hs_req->req);
+                                       if (hs_req->req.complete) {
+                                               spin_unlock(&hsotg->lock);
+                                               usb_gadget_giveback_request(
+                                                       &ep->ep, &hs_req->req);
+                                               spin_lock(&hsotg->lock);
+                                       }
                                }
 
                                /* If we have pending request, then start it */
-                               restart = !list_empty(&ep->queue);
-                               if (restart) {
-                                       hs_req = get_ep_head(ep);
-                                       s3c_hsotg_start_req(hsotg, ep,
-                                                           hs_req, false);
+                               if (!ep->req) {
+                                       restart = !list_empty(&ep->queue);
+                                       if (restart) {
+                                               hs_req = get_ep_head(ep);
+                                               s3c_hsotg_start_req(hsotg, ep,
+                                                               hs_req, false);
+                                       }
                                }
                        }
 
@@ -1020,9 +1140,10 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
                default:
                        return -ENOENT;
                }
-       } else
-               return -ENOENT;  /* currently only deal with endpoint */
-
+               break;
+       default:
+               return -ENOENT;
+       }
        return 1;
 }
 
@@ -1098,6 +1219,7 @@ static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg,
        if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
                switch (ctrl->bRequest) {
                case USB_REQ_SET_ADDRESS:
+                       hsotg->connected = 1;
                        dcfg = readl(hsotg->regs + DCFG);
                        dcfg &= ~DCFG_DEVADDR_MASK;
                        dcfg |= (le16_to_cpu(ctrl->wValue) <<
@@ -1192,7 +1314,7 @@ static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg)
        }
 
        hsotg->eps_out[0]->dir_in = 0;
-       hsotg->eps_out[0]->sent_zlp = 0;
+       hsotg->eps_out[0]->send_zlp = 0;
        hsotg->ep0_state = DWC2_EP0_SETUP;
 
        ret = s3c_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC);
@@ -1213,7 +1335,12 @@ static void s3c_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
        u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
        u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
 
-       dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", index);
+       if (hs_ep->dir_in)
+               dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n",
+                                                                       index);
+       else
+               dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n",
+                                                                       index);
 
        writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
                        DXEPTSIZ_XFERSIZE(0), hsotg->regs +
@@ -1262,6 +1389,8 @@ static void s3c_hsotg_complete_request(struct dwc2_hsotg *hsotg,
        if (hs_req->req.status == -EINPROGRESS)
                hs_req->req.status = result;
 
+       s3c_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req);
+
        hs_ep->req = NULL;
        list_del_init(&hs_req->queue);
 
@@ -1497,8 +1626,7 @@ static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
        size = grxstsr & GRXSTS_BYTECNT_MASK;
        size >>= GRXSTS_BYTECNT_SHIFT;
 
-       if (1)
-               dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
+       dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
                        __func__, grxstsr, size, epnum);
 
        switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) {
@@ -1722,6 +1850,17 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
        if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) {
                dev_dbg(hsotg->dev, "zlp packet sent\n");
                s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+               if (hsotg->test_mode) {
+                       int ret;
+
+                       ret = s3c_hsotg_set_test_mode(hsotg, hsotg->test_mode);
+                       if (ret < 0) {
+                               dev_dbg(hsotg->dev, "Invalid Test #%d\n",
+                                               hsotg->test_mode);
+                               s3c_hsotg_stall_ep0(hsotg);
+                               return;
+                       }
+               }
                s3c_hsotg_enqueue_setup(hsotg);
                return;
        }
@@ -1756,9 +1895,9 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
        }
 
        /* Zlp for all endpoints, for ep0 only in DATA IN stage */
-       if (hs_ep->sent_zlp) {
+       if (hs_ep->send_zlp) {
                s3c_hsotg_program_zlp(hsotg, hs_ep);
-               hs_ep->sent_zlp = 0;
+               hs_ep->send_zlp = 0;
                /* transfer will be completed on next complete interrupt */
                return;
        }
@@ -2033,6 +2172,7 @@ void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
                return;
 
        hsotg->connected = 0;
+       hsotg->test_mode = 0;
 
        for (ep = 0; ep < hsotg->num_of_eps; ep++) {
                if (hsotg->eps_in[ep])
@@ -2136,9 +2276,13 @@ static int s3c_hsotg_corereset(struct dwc2_hsotg *hsotg)
  *
  * Issue a soft reset to the core, and await the core finishing it.
  */
-void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
+void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
+                                               bool is_usb_reset)
 {
-       s3c_hsotg_corereset(hsotg);
+       u32 val;
+
+       if (!is_usb_reset)
+               s3c_hsotg_corereset(hsotg);
 
        /*
         * we must now enable ep0 ready for host detection and then
@@ -2146,14 +2290,16 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
         */
 
        /* set the PLL on, remove the HNP/SRP and set the PHY */
+       val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
        writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |
-              (0x5 << 10), hsotg->regs + GUSBCFG);
+              (val << GUSBCFG_USBTRDTIM_SHIFT), hsotg->regs + GUSBCFG);
 
        s3c_hsotg_init_fifo(hsotg);
 
-       __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+       if (!is_usb_reset)
+               __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
 
-       writel(1 << 18 | DCFG_DEVSPD_HS,  hsotg->regs + DCFG);
+       writel(DCFG_EPMISCNT(1) | DCFG_DEVSPD_HS,  hsotg->regs + DCFG);
 
        /* Clear any pending OTG interrupts */
        writel(0xffffffff, hsotg->regs + GOTGINT);
@@ -2222,9 +2368,11 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
        s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
        s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
 
-       __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
-       udelay(10);  /* see openiboot */
-       __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+       if (!is_usb_reset) {
+               __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+               udelay(10);  /* see openiboot */
+               __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+       }
 
        dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL));
 
@@ -2253,8 +2401,10 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
                readl(hsotg->regs + DOEPCTL0));
 
        /* clear global NAKs */
-       writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK | DCTL_SFTDISCON,
-              hsotg->regs + DCTL);
+       val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
+       if (!is_usb_reset)
+               val |= DCTL_SFTDISCON;
+       __orr32(hsotg->regs + DCTL, val);
 
        /* must be at-least 3ms to allow bus to see disconnect */
        mdelay(3);
@@ -2300,7 +2450,6 @@ irq_retry:
                writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
 
                s3c_hsotg_irq_enumdone(hsotg);
-               hsotg->connected = 1;
        }
 
        if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
@@ -2338,6 +2487,9 @@ irq_retry:
 
                writel(GINTSTS_USBRST, hsotg->regs + GINTSTS);
 
+               /* Report disconnection if it is not already done. */
+               s3c_hsotg_disconnect(hsotg);
+
                if (usb_status & GOTGCTL_BSESVLD) {
                        if (time_after(jiffies, hsotg->last_rst +
                                       msecs_to_jiffies(200))) {
@@ -2345,8 +2497,7 @@ irq_retry:
                                kill_all_requests(hsotg, hsotg->eps_out[0],
                                                          -ECONNRESET);
 
-                               s3c_hsotg_core_init_disconnected(hsotg);
-                               s3c_hsotg_core_connect(hsotg);
+                               s3c_hsotg_core_init_disconnected(hsotg, true);
                        }
                }
        }
@@ -2438,12 +2589,12 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
        struct s3c_hsotg_ep *hs_ep = our_ep(ep);
        struct dwc2_hsotg *hsotg = hs_ep->parent;
        unsigned long flags;
-       int index = hs_ep->index;
+       unsigned int index = hs_ep->index;
        u32 epctrl_reg;
        u32 epctrl;
        u32 mps;
-       int dir_in;
-       int i, val, size;
+       unsigned int dir_in;
+       unsigned int i, val, size;
        int ret = 0;
 
        dev_dbg(hsotg->dev,
@@ -2527,11 +2678,24 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
                break;
        }
 
+       /* If fifo is already allocated for this ep */
+       if (hs_ep->fifo_index) {
+               size =  hs_ep->ep.maxpacket * hs_ep->mc;
+               /* If bigger fifo is required deallocate current one */
+               if (size > hs_ep->fifo_size) {
+                       hsotg->fifo_map &= ~(1 << hs_ep->fifo_index);
+                       hs_ep->fifo_index = 0;
+                       hs_ep->fifo_size = 0;
+               }
+       }
+
        /*
         * if the hardware has dedicated fifos, we must give each IN EP
         * a unique tx-fifo even if it is non-periodic.
         */
-       if (dir_in && hsotg->dedicated_fifos) {
+       if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) {
+               u32 fifo_index = 0;
+               u32 fifo_size = UINT_MAX;
                size = hs_ep->ep.maxpacket*hs_ep->mc;
                for (i = 1; i < hsotg->num_of_eps; ++i) {
                        if (hsotg->fifo_map & (1<<i))
@@ -2540,19 +2704,22 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
                        val = (val >> FIFOSIZE_DEPTH_SHIFT)*4;
                        if (val < size)
                                continue;
-                       hsotg->fifo_map |= 1<<i;
-
-                       epctrl |= DXEPCTL_TXFNUM(i);
-                       hs_ep->fifo_index = i;
-                       hs_ep->fifo_size = val;
-                       break;
+                       /* Search for smallest acceptable fifo */
+                       if (val < fifo_size) {
+                               fifo_size = val;
+                               fifo_index = i;
+                       }
                }
-               if (i == hsotg->num_of_eps) {
+               if (!fifo_index) {
                        dev_err(hsotg->dev,
                                "%s: No suitable fifo found\n", __func__);
                        ret = -ENOMEM;
                        goto error;
                }
+               hsotg->fifo_map |= 1 << fifo_index;
+               epctrl |= DXEPCTL_TXFNUM(fifo_index);
+               hs_ep->fifo_index = fifo_index;
+               hs_ep->fifo_size = fifo_size;
        }
 
        /* for non control endpoints, set PID to D0 */
@@ -2578,7 +2745,7 @@ error:
  * s3c_hsotg_ep_disable - disable given endpoint
  * @ep: The endpoint to disable.
  */
-static int s3c_hsotg_ep_disable(struct usb_ep *ep)
+static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
 {
        struct s3c_hsotg_ep *hs_ep = our_ep(ep);
        struct dwc2_hsotg *hsotg = hs_ep->parent;
@@ -2621,6 +2788,10 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
        return 0;
 }
 
+static int s3c_hsotg_ep_disable(struct usb_ep *ep)
+{
+       return s3c_hsotg_ep_disable_force(ep, false);
+}
 /**
  * on_list - check request is on the given endpoint
  * @ep: The endpoint to check.
@@ -2808,6 +2979,7 @@ static void s3c_hsotg_phy_disable(struct dwc2_hsotg *hsotg)
  */
 static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
 {
+       u32 trdtim;
        /* unmask subset of endpoint interrupts */
 
        writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
@@ -2823,12 +2995,6 @@ static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
        /* Be in disconnected state until gadget is registered */
        __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
 
-       if (0) {
-               /* post global nak until we're ready */
-               writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK,
-                      hsotg->regs + DCTL);
-       }
-
        /* setup fifos */
 
        dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
@@ -2838,8 +3004,10 @@ static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
        s3c_hsotg_init_fifo(hsotg);
 
        /* set the PLL on, remove the HNP/SRP and set the PHY */
-       writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10),
-              hsotg->regs + GUSBCFG);
+       trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
+       writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |
+               (trdtim << GUSBCFG_USBTRDTIM_SHIFT),
+               hsotg->regs + GUSBCFG);
 
        if (using_dma(hsotg))
                __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN);
@@ -2901,7 +3069,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
 
        spin_lock_irqsave(&hsotg->lock, flags);
        s3c_hsotg_init(hsotg);
-       s3c_hsotg_core_init_disconnected(hsotg);
+       s3c_hsotg_core_init_disconnected(hsotg, false);
        hsotg->enabled = 0;
        spin_unlock_irqrestore(&hsotg->lock, flags);
 
@@ -2994,9 +3162,11 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
        if (is_on) {
                clk_enable(hsotg->clk);
                hsotg->enabled = 1;
+               s3c_hsotg_core_init_disconnected(hsotg, false);
                s3c_hsotg_core_connect(hsotg);
        } else {
                s3c_hsotg_core_disconnect(hsotg);
+               s3c_hsotg_disconnect(hsotg);
                hsotg->enabled = 0;
                clk_disable(hsotg->clk);
        }
@@ -3008,11 +3178,52 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
+static int s3c_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+       struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+       unsigned long flags;
+
+       dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active);
+       spin_lock_irqsave(&hsotg->lock, flags);
+
+       if (is_active) {
+               /* Kill any ep0 requests as controller will be reinitialized */
+               kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
+               s3c_hsotg_core_init_disconnected(hsotg, false);
+               if (hsotg->enabled)
+                       s3c_hsotg_core_connect(hsotg);
+       } else {
+               s3c_hsotg_core_disconnect(hsotg);
+               s3c_hsotg_disconnect(hsotg);
+       }
+
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+       return 0;
+}
+
+/**
+ * s3c_hsotg_vbus_draw - report bMaxPower field
+ * @gadget: The usb gadget state
+ * @mA: Amount of current
+ *
+ * Report how much power the device may consume to the phy.
+ */
+static int s3c_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+
+       if (IS_ERR_OR_NULL(hsotg->uphy))
+               return -ENOTSUPP;
+       return usb_phy_set_power(hsotg->uphy, mA);
+}
+
 static const struct usb_gadget_ops s3c_hsotg_gadget_ops = {
        .get_frame      = s3c_hsotg_gadget_getframe,
        .udc_start              = s3c_hsotg_udc_start,
        .udc_stop               = s3c_hsotg_udc_stop,
        .pullup                 = s3c_hsotg_pullup,
+       .vbus_session           = s3c_hsotg_vbus_session,
+       .vbus_draw              = s3c_hsotg_vbus_draw,
 };
 
 /**
@@ -3085,7 +3296,7 @@ static int s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
        /* check hardware configuration */
 
        cfg = readl(hsotg->regs + GHWCFG2);
-       hsotg->num_of_eps = (cfg >> 10) & 0xF;
+       hsotg->num_of_eps = (cfg >> GHWCFG2_NUM_DEV_EP_SHIFT) & 0xF;
        /* Add ep0 */
        hsotg->num_of_eps++;
 
@@ -3097,7 +3308,7 @@ static int s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
        hsotg->eps_out[0] = hsotg->eps_in[0];
 
        cfg = readl(hsotg->regs + GHWCFG1);
-       for (i = 1; i < hsotg->num_of_eps; i++, cfg >>= 2) {
+       for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) {
                ep_type = cfg & 3;
                /* Direction in or both */
                if (!(ep_type & 2)) {
@@ -3116,10 +3327,10 @@ static int s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
        }
 
        cfg = readl(hsotg->regs + GHWCFG3);
-       hsotg->fifo_mem = (cfg >> 16);
+       hsotg->fifo_mem = (cfg >> GHWCFG3_DFIFO_DEPTH_SHIFT);
 
        cfg = readl(hsotg->regs + GHWCFG4);
-       hsotg->dedicated_fifos = (cfg >> 25) & 1;
+       hsotg->dedicated_fifos = (cfg >> GHWCFG4_DED_FIFO_SHIFT) & 1;
 
        dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
                 hsotg->num_of_eps,
@@ -3144,8 +3355,8 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
                 readl(regs + DCFG), readl(regs + DCTL),
                 readl(regs + DIEPMSK));
 
-       dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
-                readl(regs + GAHBCFG), readl(regs + 0x44));
+       dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n",
+                readl(regs + GAHBCFG), readl(regs + GHWCFG1));
 
        dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
                 readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ));
@@ -3181,6 +3392,103 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
 }
 
 /**
+ * testmode_write - debugfs: change usb test mode
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry modify the current usb test mode.
+ */
+static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
+               count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc2_hsotg       *hsotg = s->private;
+       unsigned long           flags;
+       u32                     testmode = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "test_j", 6))
+               testmode = TEST_J;
+       else if (!strncmp(buf, "test_k", 6))
+               testmode = TEST_K;
+       else if (!strncmp(buf, "test_se0_nak", 12))
+               testmode = TEST_SE0_NAK;
+       else if (!strncmp(buf, "test_packet", 11))
+               testmode = TEST_PACKET;
+       else if (!strncmp(buf, "test_force_enable", 17))
+               testmode = TEST_FORCE_EN;
+       else
+               testmode = 0;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       s3c_hsotg_set_test_mode(hsotg, testmode);
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+       return count;
+}
+
+/**
+ * testmode_show - debugfs: show usb test mode state
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows which usb test mode is currently enabled.
+ */
+static int testmode_show(struct seq_file *s, void *unused)
+{
+       struct dwc2_hsotg *hsotg = s->private;
+       unsigned long flags;
+       int dctl;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       dctl = readl(hsotg->regs + DCTL);
+       dctl &= DCTL_TSTCTL_MASK;
+       dctl >>= DCTL_TSTCTL_SHIFT;
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       switch (dctl) {
+       case 0:
+               seq_puts(s, "no test\n");
+               break;
+       case TEST_J:
+               seq_puts(s, "test_j\n");
+               break;
+       case TEST_K:
+               seq_puts(s, "test_k\n");
+               break;
+       case TEST_SE0_NAK:
+               seq_puts(s, "test_se0_nak\n");
+               break;
+       case TEST_PACKET:
+               seq_puts(s, "test_packet\n");
+               break;
+       case TEST_FORCE_EN:
+               seq_puts(s, "test_force_enable\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %d\n", dctl);
+       }
+
+       return 0;
+}
+
+static int testmode_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, testmode_show, inode->i_private);
+}
+
+static const struct file_operations testmode_fops = {
+       .owner          = THIS_MODULE,
+       .open           = testmode_open,
+       .write          = testmode_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
  * state_show - debugfs: show overall driver and device state.
  * @seq: The seq file to write to.
  * @v: Unused parameter.
@@ -3408,13 +3716,21 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
 
        /* create general state file */
 
-       hsotg->debug_file = debugfs_create_file("state", 0444, root,
+       hsotg->debug_file = debugfs_create_file("state", S_IRUGO, root,
                                                hsotg, &state_fops);
 
        if (IS_ERR(hsotg->debug_file))
                dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
 
-       hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root,
+       hsotg->debug_testmode = debugfs_create_file("testmode",
+                                       S_IRUGO | S_IWUSR, root,
+                                       hsotg, &testmode_fops);
+
+       if (IS_ERR(hsotg->debug_testmode))
+               dev_err(hsotg->dev, "%s: failed to create testmode\n",
+                               __func__);
+
+       hsotg->debug_fifo = debugfs_create_file("fifo", S_IRUGO, root,
                                                hsotg, &fifo_fops);
 
        if (IS_ERR(hsotg->debug_fifo))
@@ -3426,7 +3742,7 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
 
                ep = hsotg->eps_out[epidx];
                if (ep) {
-                       ep->debugfs = debugfs_create_file(ep->name, 0444,
+                       ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
                                                          root, ep, &ep_fops);
 
                        if (IS_ERR(ep->debugfs))
@@ -3440,7 +3756,7 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
 
                ep = hsotg->eps_in[epidx];
                if (ep) {
-                       ep->debugfs = debugfs_create_file(ep->name, 0444,
+                       ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
                                                          root, ep, &ep_fops);
 
                        if (IS_ERR(ep->debugfs))
@@ -3468,6 +3784,7 @@ static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg)
        }
 
        debugfs_remove(hsotg->debug_file);
+       debugfs_remove(hsotg->debug_testmode);
        debugfs_remove(hsotg->debug_fifo);
        debugfs_remove(hsotg->debug_root);
 }
@@ -3612,6 +3929,19 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        /* usb phy enable */
        s3c_hsotg_phy_enable(hsotg);
 
+       /*
+        * Force Device mode before initialization.
+        * This allows correctly configuring fifo for device mode.
+        */
+       __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEHOSTMODE);
+       __orr32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
+
+       /*
+        * According to Synopsys databook, this sleep is needed for the force
+        * device mode to take effect.
+        */
+       msleep(25);
+
        s3c_hsotg_corereset(hsotg);
        ret = s3c_hsotg_hw_cfg(hsotg);
        if (ret) {
@@ -3621,6 +3951,9 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 
        s3c_hsotg_init(hsotg);
 
+       /* Switch back to default configuration */
+       __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
+
        hsotg->ctrl_buff = devm_kzalloc(hsotg->dev,
                        DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
        if (!hsotg->ctrl_buff) {
@@ -3782,7 +4115,7 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg)
                s3c_hsotg_phy_enable(hsotg);
 
                spin_lock_irqsave(&hsotg->lock, flags);
-               s3c_hsotg_core_init_disconnected(hsotg);
+               s3c_hsotg_core_init_disconnected(hsotg, false);
                if (hsotg->enabled)
                        s3c_hsotg_core_connect(hsotg);
                spin_unlock_irqrestore(&hsotg->lock, flags);