USB: Merge the following changes from UMG 2.6.35 tree
authorFei Yang <fei.yang@intel.com>
Thu, 6 Oct 2011 23:27:37 +0000 (16:27 -0700)
committermgross <mark.gross@intel.com>
Wed, 9 Nov 2011 21:15:39 +0000 (13:15 -0800)
Signed-off-by: Fengwei Yin <fengwei.yin@intel.com>
Signed-off-by: Fei Yang <fei.yang@intel.com>
commit 6a9f1076fde6cbcac68d51efe0bf8c8776d57f42
Author: jzhuan5 <jin.can.zhuang@intel.com>
Date:   Fri Sep 16 17:03:33 2011 -0400

    usb: langwell_udc: protect access to ep->desc and clear Auto low power featu

    BZ: 9110

    Two issue fixed:
    1. When langwell_ep_queue is being called, there could be interrupts, then e
    is set NULL, after returning from interrupt, langwell_ep_queue() calls queue
    which will access ep->desc without checking it, this leads to NULL pointer k

    The patch adds lock protection to ep->desc to avoid this.

    2. The auto low power feature is causing fabric error when calling langwell_
    in some extreme timing situtation. In this bug, langwell_ep_disable() is cal
    after bus suspend is received by device controller. If auto low power featur
    PHCD bit will be set by controller automatically. Then, langwell_ep_disable(
    fabric error.

    Since langwell_udc driver has not utilized this feature, this patch simply d

    Change-Id: Ia95d9ee9dee22c19e55f046b62a864a2fb4bd084
Signed-off-by: jzhuan5 <jin.can.zhuang@intel.com>
    Reviewed-on: http://android.intel.com:8080/18772
Reviewed-by: Yin, Fengwei <fengwei.yin@intel.com>
Tested-by: Yin, Fengwei <fengwei.yin@intel.com>
commit cfbe81d988a2201ca0a02fa33481f0f014cab3ab
Author: Wu, Hao <hao.wu@intel.com>
Date:   Thu Sep 1 22:24:24 2011 +0800

    usb/penwell_otg: increase ulpi access timeout

    BZ:  7272

    This patch increase the timeout for each ulpi access via
    PNW USB controller to MSIC ULPI registers, to increase
    tolerance for bad case.

    Change-Id: I5ee9769ba990f591744d08e4fc2147037f57fab6
Signed-off-by: Wu, Hao <hao.wu@intel.com>
    Reviewed-on: http://android.intel.com:8080/17034
Reviewed-by: buildbot <buildbot@intel.com>
Reviewed-by: Yin, Fengwei <fengwei.yin@intel.com>
Tested-by: Yin, Fengwei <fengwei.yin@intel.com>
commit 02bbb3bf258225f59fcd4f28827ae77d817db2d6
Author: jzhuan5 <jin.can.zhuang@intel.com>
Date:   Thu Sep 1 16:38:58 2011 -0400

    usb: client: Fix the issue of test mode fail in TEST_PACKET

    BZ:  8285 8779

    PET sends set_feature request to enable USB client to a state of TEST MODE.
    After the completion of status stage, USB client should enable TEST MODE by
    programming PORTSC1 register. Also stop TEST MODE after USB device power
    cycle according to USB Spec.

    Change-Id: Ie973dabd227ddde6fdbea30e55866ee07b9bb884
Signed-off-by: jzhuan5 <jin.can.zhuang@intel.com>
Signed-off-by: Wu, Hao <hao.wu@intel.com>
    Reviewed-on: http://android.intel.com:8080/17146
Reviewed-by: Yin, Fengwei <fengwei.yin@intel.com>
Tested-by: Yin, Fengwei <fengwei.yin@intel.com>
commit 87f8a45120ee13c30100d687499be97c6d31bf04
Author: Yu Wang <yu.y.wang@intel.com>
Date:   Fri Aug 26 17:14:19 2011 +0800

    usb: langwell_udc: fix flush ep met fabric error.

    BZ:  7888

    When UDC flush ep, sometimes system met fabric error. The root cause is
    before flush ep, PHY would exit low power mode. And there is a latency
    in HW did this operation, if driver access UDC during this latency,
    system will meet fabric error.

    This patch add 3 millisecond delay to ensure the PHY HW exit low power
    mode, then operate UDC.

    Change-Id: I39992616c58e3c89789830413a323439ba785764
Signed-off-by: Yu Wang <yu.y.wang@intel.com>
commit d4252773bed09a139437efc975c78b1d684c527e
Author: jzhuan5 <jin.can.zhuang@intel.com>
Date:   Fri Aug 26 12:00:58 2011 -0400

    usb: otg: Disable MSIC interrupt when system is shutting down

    BZ:  7832

    This patch implements shutdown callback of penwell_otg driver.
    The shutdown callback disables MSIC interrupts to prevent from
    disturbing the process of system shutdown.
Signed-off-by: jzhuan5 <jin.can.zhuang@intel.com>
    Change-Id: I3de7f54d09b5b9b06304775403115e5932b28b72

commit 14a840ae3eb1d4d7dc886e332abd8afb0840633d
Author: Wu, Hao <hao.wu@intel.com>
Date:   Tue Aug 16 01:44:35 2011 +0800

    usb/penwell_otg: fix PD_DCP detection compliance Test issue.

    BZ:  4360

    This patch add 1ms sleep between Primary and Secondary Detection,
    and assert VDPSRC when DCP detected and attached. This resolved
    BC1.2 compliance test case PD_DCP issue.

    Change-Id: I9cf3b71e33a795748702a3cf582b8fa51abc6a11
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit 1c3d68c874898e90442c2dfb541c8dd2397a3749
Author: Wu, Hao <hao.wu@intel.com>
Date:   Wed Aug 3 04:00:10 2011 +0800

    usb/langwell_udc: fix some issue to avoid blocking into D0i1.

    BZ:  6378
    This patch is from Borqs, resolve issue if ep flush timeout, then
    USB D0i1 state will be blocked.

    Change-Id: I9697cc2c310db20b337e8dd9032f1eb951a0f2e5
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit 63e1d6fa995a95991b668d34126017629909099c
Author: Wu, Hao <hao.wu@intel.com>
Date:   Fri Jul 29 19:02:15 2011 +0800

    usb/penwell_otg: manual charger detection flow

    BZ:  2921

    This is a SW workaround for a hardware issue which cause charging
    failure, using manual charger detection flow instead of original one
    to avoid this hardware issue.
    Please note that the new flow using ULPI, only works on PNW C0 or later
    version.

    Change-Id: I1941c2dd7364b13b7354995f0eb5a3a6ec2da402
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit 1ad65047b445da5455da82b8b05b168516979b56
Author: Wu, Hao <hao.wu@intel.com>
Date:   Thu Jul 28 02:45:12 2011 +0800

    usb/penwell_otg: enable OTG_VBUS_OFF test mode for compliance test

    BZ:  5895

    This patch enabled OTG_VBUS_OFF test mode in driver for USB OTG 2.0 complian
    case CT_A_CAP (OTG Compliance Plan 8.1.2 A-UUT Bypass Capacitance).

    Change-Id: I07891cb9d1138e620361b30c7d894b0f5f4dfec4
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit 105bf83d769f9b5a4fc13287595080a236df4ece
Author: Wu, Hao <hao.wu@intel.com>
Date:   Fri Jul 15 03:50:30 2011 +0800
    usb/penwell:  fix incorrect charging current when USB is in unconfigured sta

    BZ: 5146

    This patch is for USB OTG2.0 Compliance issue, after a USB reset, USB will
    be back to unconfigured state, then only can draw less than IB_UNCFG max
    (2.5mA) current from connected SDP. This patch add related action triggered
    by USB reset event.

    Change-Id: I4d325de485e468b0bd808c0ccebc2aadea95768c
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit 03da966f597139a67f7644a7b17631d06cda5c5e
Author: Yu Wang <yu.y.wang@intel.com>
Date:   Thu Jul 14 16:57:14 2011 +0800

    usb:  langwell_udc: fix pull up USB met fabric error issue.

    BZ: 5087

    After enabled the "USB tethering" from Android settings application,
    pulled up USB cable, board would meet fabric error. The root cause is
    after pulled up USB cable, UDC would go to D0I1 mode. And Android
    framework would find USB cabled was disconnected, then wrote zero to funtion
    enable interface of sysfs. But this sysfs interface hadn't resume UDC to D0
    mode before operated UDC HW, then met fabric error.

    This patch fixes this issue by resume UDC from DOI1 before operating HW
    in langwell_pullup function.

    Change-Id: I9b7c698afec79f0ef355c3053ef9538e8b9dd4e6
Signed-off-by: Yu Wang <yu.y.wang@intel.com>
commit ed3cd9c69c33d5a70f4918e8822413dd95001007
Author: Wu, Hao <hao.wu@intel.com>
Date:   Wed Jul 13 02:29:45 2011 +0800

    usb/penwell:  add SRP test mode support

    BZ: 4974
    This patch is for SRP Test mode support, please refer to USB OTG 2.0
    Spec 6.4.3, OTG Compliance Test 6.3.4.

    Change-Id: Iaba1d89b79c28862a0239c0cf5cc57a00fef8e8c
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit b49721682faf6a42aecbddfa71ebb10d537cf661
Author: Jiebing Li <jiebing.li@intel.com>
Date:   Fri Jul 1 04:10:08 2011 +0800

    usb:  langwell_udc: fix pull-up enable issue in langwell_pullup()

    BZ: 4154

    Sometimes USB host sends bus_suspend request to device due to
    some reason. When device receives the request, PHY will be put
    into low power suspend by device driver. If at this time
    langwell_pullup() is called by gadget driver to set USBCMD
    Run/Stop bit, the pull-up on D+ will not be enabled as expected.

    This patch fixes the issue by exiting PHY low power in langwell_pullup().

    Change-Id: I1b9836f57e0a25e16eeaa31b3c4319e811a542ad
Signed-off-by: Jiebing Li <jiebing.li@intel.com>
commit 2e1aa820ecc706cde4798ead132629b276bcc84f
Author: Hao Wu <hao.wu@intel.com>
Date:   Mon Jun 20 10:43:42 2011 +0800

    usb/penwell_otg:  enable timer ta_wait_bcon for wait connection state.

    BZ: 4357

    After USB A-cable is inserted into OTG port, USB driver will enable
    Host stack and VBUS power supply, then wait device to connect. Per
    spec, enable the wait timeout as 15s (< 30s max).
    This is for OTG2.0 Compliance Test: 6.2.2 A_UUT Power up Test.

    Change-Id: I4a9ae8c23c26aabb461fa7c5c77b9057cbe6290d
Signed-off-by: Wu, Hao <hao.wu@intel.com>
commit 1163dcda8ec382b08299bf09d01f1f76ba977da7
Author: Hao Wu <hao.wu@intel.com>
Date:   Mon May 30 20:33:41 2011 +0800

    usb/langwell_udc: hold wakelock when USB is connected and not suspended

    BZ: 2824

    This patch enable USB udc driver to hold wake lock when USB is connected
    and usb bus is active state. This will prevent system from trying to enter
    S3 when usb is still alive.

    Change-Id: Ibc2ae6a985ea6d9168265c3ce4227f4a4309eba4
Signed-off-by: Hao Wu <hao.wu@intel.com>
commit 500c0f18a30a222620027446294d913fa3e9a60e
Author: Shanyu Zhao <shanyu.zhao@intel.com>
Date:   Tue May 17 15:31:55 2011 -0700

    USB: Fix commanded stall feature in the device controller

    BZ: 2314

    usbtest TEST CASE 13 - endpoint halt feature fails. Commanded stall
    occurs when host explicitly calls the endpoint's halt feature.
    The set_halt function at the gadget side will not halt theendpoint
    if the queue is not empty. Therefore when the host calls the
    halt feature for some gadget function such as the gadget zero, which
    always put a usb_request in the queue, the halt always  fails.

    To fix the failure, for commanded stall don't check for the queue.
    Also when reset the endpoint the halt flag shall be cleared manually.

    Change-Id: I1f5789a4c8115d46c800ee5b808141cab9c2da20
Signed-off-by: Shanyu Zhao <shanyu.zhao@intel.com>
Signed-off-by: Jiebing Li <jiebing.li@intel.com>
commit acb6ef93331fb854408ba0748e26ae6e18c0b653
Author: Shanyu Zhao <shanyu.zhao@intel.com>
Date:   Tue May 17 14:39:52 2011 -0700

    USB:  disable HW zero length termination for device control endpoints
    BZ: 2767

    Since the control endpoints know the expected number of bytes in a
    transaction, zero length termination (zlt) is not needed. If enabled
    the device controller would wait indefinitely for the USB host to send
    an zero length packet which never  happens.

    This fixes the failure of the usbtest TEST CASE 14.

    Change-Id: Ib31f2c6dd87b60c669c265bb87afbead056d536f
Signed-off-by: Shanyu Zhao <shanyu.zhao@intel.com>
commit 35eaa2fdf470e9b6bf922ba67ca5ca48fdb8bfd1
Author: Hao Wu <hao.wu@intel.com>
Date:   Fri May 6 13:26:25 2011 +0800

    usb: penwell_otg: use separate suspend/resume functions for D3

    BZ: 1424

    This patch updated penwell_otg driver to use separate resume/suspend
    function for D3 instead of reuse runtime pm functions, they contain
     more state machine handling for USB D3 state, including PHY Low
    power mode setting, timer delete and state transition. It resolved
     unstable issue caused by incorrect handle on USB states and events
     when D3 suspend/resume.

    Change-Id: I94d395a2851b5cfda0c8e2dd49ebd83c92e6aa83
Signed-off-by: Hao Wu <hao.wu@intel.com>
commit e29a44d2438cd13521af9b36719f00ebe8527593
Author: Sundar Iyer <sundar.iyer@intel.com>
Date:   Mon Apr 25 18:53:52 2011 +0530

    usb/penwell_otg: use dev_pm_ops interfaces for D3 suspend/resume.

    BZ:#1378/#1301

    This patch updates the penwell_otg to use .suspend/.resume in the dev_pm_ops
     interface instead of the legacy pci driver suspend/resume functions.
    This patch also removes duplicate pci related opeartions in suspend/resume
    functions.

    Change-Id: I66f2bf841979bc40787d3b3b884583c7b30511d8
Signed-off-by: Sundar Iyer <sundar.iyer@intel.com>
Signed-off-by: Hao Wu <hao.wu@intel.com>
commit 6e2bf9dc73b990dc693ed6413d2f7ddc33df8615
Author: Jiebing Li <jiebing.li@intel.com>
Date:   Tue Apr 19 15:37:46 2011 +0800

    usb: langwell_udc: fix cable unplug issues

    BZ: 1001

    This patch fixed stop USB peripheral stack issue after received unplug event

    Two issues are fixed in this patch:
    1. add dtd_pool pointer check in order to avoid dtd pool free error
    2. remove PHY low power set in order to avoid EP flush timeout

    Change-Id: Ib259268cdffcb0ad30a19dd3258992efe63720cb
Signed-off-by: Jiebing Li <jiebing.li@intel.com>
commit 9e6b9018a137bb68d8c55bcd9a9096a1134693d3
Author: Hao Wu <hao.wu@intel.com>
Date:   Tue Apr 19 14:59:34 2011 +0800

    usb: penwell_otg: fix missing unplug USB cable event.

    BZ: 1001

    This patch is for BZ1001, mainly solve missing unplug USB wall charger
    (DCP) event when USB is in D0i3 and charging from DCP.

    Main change in penwell_otg:
    - Use PNW USB OTGSC status register to check wakeup event.
    - Ensure mode is set and PHY is in low power mode before enter D0i3
    - Remove duplicate PHY low power mode setting.

    Change-Id: I4c842a7b8a10332360b7b7695139666870094284
Signed-off-by: Hao Wu <hao.wu@intel.com>
commit c2846926367114bead0e6cd0f1b4dff6fc6a121f
Author: Hao Wu <hao.wu@intel.com>
Date:   Fri Apr 15 11:36:30 2011 +0800

    usb: penwell_otg: fixing SRP failure.

    Fixing patch for Sighting 3742776: SRP failed

    Change-Id: I64b9446b7ba8b5e87b1e95e87ea20b2682c071f4
Signed-off-by: Hao Wu <hao.wu@intel.com>
commit 3f35456f90c7ff997e078cc9083cfefda4bc4f02
Author: Jiebing Li <jiebing.li@intel.com>
Date:   Thu Mar 10 16:56:26 2011 +0800

    runtime PM mode change in gadget unregister operation

    put usb client to D0 mode in gagdet unregister operation and put it
    back to D0i3 after the operation done

    Change-Id: Ib8fe33f9f46947ed4a9e26458db75f2ae16318d3
Signed-off-by: Jiebing Li <jiebing.li@intel.com>
commit d17c4c027c5c8e0e2e42d9c637cf4452c204b443
Author: Jiebing Li <jiebing.li@intel.com>
Date:   Fri Aug 20 13:49:09 2010 -0700

    linux-2.6.36-usb-penwell-otg-add-aca-device-support.patch

commit 80900b4c8976ec78b12393d64244e2f186998736
Author: Hao Wu <hao.wu@intel.com>
Date:   Fri Aug 20 13:49:09 2010 -0700

    linux-2.6.36-usb-penwell_otg-HACK-resume-controller-before-reg-access.patch

commit f5ec09219efa41149a38930e84cd77dd402ed9dc
Author: Hao Wu <hao.wu@intel.com>
Date:   Fri Aug 20 13:49:09 2010 -0700

    linux-2.6.36-usb-penwell_otg-add-phy-config.patch

commit ede32384e6a8021d6fa9627ead3ac378bafe60e7
Author: Hao Wu <hao.wu@intel.com>
Date:   Fri Aug 20 13:49:09 2010 -0700

    linux-2.6.36-usb-penwell_otg-update-otg-state-machine-for-runtime_pm.patch

commit 7f1584ff3eac1fa4c01762c071c0b5bdeaba0da9
Author: Hao Wu <hao.wu@intel.com>
Date:   Fri Aug 20 13:49:09 2010 -0700

    linux-2.6.36-usb-langwell_udc-add-runtime-pm-support-for-otg.patch

Change-Id: I06a291cee179b1efe450eadf96e278434246742a

drivers/usb/gadget/langwell_udc.c
drivers/usb/gadget/langwell_udc.h
drivers/usb/otg/penwell_otg.c
include/linux/usb/ch9.h
include/linux/usb/gadget.h
include/linux/usb/intel_mid_otg.h
include/linux/usb/langwell_udc.h
include/linux/usb/penwell_otg.h

index b2fa281..d942564 100644 (file)
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/wakelock.h>
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
@@ -73,6 +75,7 @@ langwell_ep0_desc = {
        .wMaxPacketSize =       EP0_MAX_PKT_SIZE,
 };
 
+static void ep_set_halt(struct langwell_ep *ep, int value);
 
 /*-------------------------------------------------------------------------*/
 /* debugging */
@@ -192,6 +195,21 @@ static char *type_string(const struct usb_endpoint_descriptor *desc)
        return "control";
 }
 
+#ifdef OTG_TRANSCEIVER
+static void langwell_udc_notify_otg(unsigned long event)
+{
+       struct langwell_udc     *dev = the_controller;
+
+       if (dev && dev->iotg && event)
+               atomic_notifier_call_chain(&dev->iotg->iotg_notifier,
+                               event, dev->iotg);
+}
+#else
+static inline void langwell_udc_notify_otg(unsigned long event);
+{
+       return ;
+}
+#endif
 
 /* configure endpoint control registers */
 static void ep_reset(struct langwell_ep *ep, unsigned char ep_num,
@@ -218,6 +236,9 @@ static void ep_reset(struct langwell_ep *ep, unsigned char ep_num,
 
        writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
 
+       /* has to manually clear halt for non-control endpoints */
+       ep_set_halt(ep, 0);
+
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 }
 
@@ -242,9 +263,12 @@ static void ep0_reset(struct langwell_udc *dev)
                ep->dqh->dqh_ios = 1;
                ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE;
 
-               /* enable ep0-in HW zero length termination select */
-               if (is_in(ep))
-                       ep->dqh->dqh_zlt = 0;
+               /*
+                * Disable HW zero length termination
+                * select for control endpoints.
+                */
+               ep->dqh->dqh_zlt = 1;
+
                ep->dqh->dqh_mult = 0;
 
                ep->dqh->dtd_next = DTD_TERM;
@@ -411,12 +435,14 @@ static void done(struct langwell_ep *ep, struct langwell_request *req,
                status = req->req.status;
 
        /* free dTD for the request */
-       next_dtd = req->head;
-       for (i = 0; i < req->dtd_count; i++) {
-               curr_dtd = next_dtd;
-               if (i != req->dtd_count - 1)
-                       next_dtd = curr_dtd->next_dtd_virt;
-               dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
+       if (dev->dtd_pool) {
+               next_dtd = req->head;
+               for (i = 0; i < req->dtd_count; i++) {
+                       curr_dtd = next_dtd;
+                       if (i != req->dtd_count - 1)
+                               next_dtd = curr_dtd->next_dtd_virt;
+                       dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
+               }
        }
 
        if (req->mapped) {
@@ -490,6 +516,8 @@ static int langwell_ep_disable(struct usb_ep *_ep)
        if (!_ep || !ep->desc)
                return -EINVAL;
 
+       pm_runtime_get_sync(&dev->pdev->dev);
+
        spin_lock_irqsave(&dev->lock, flags);
 
        /* disable endpoint control register */
@@ -509,6 +537,8 @@ static int langwell_ep_disable(struct usb_ep *_ep)
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
+       pm_runtime_put_sync(&dev->pdev->dev);
+
        dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name);
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 
@@ -660,7 +690,7 @@ static struct langwell_dtd *build_dtd(struct langwell_request *req,
                unsigned *length, dma_addr_t *dma, int *is_last)
 {
        u32                      buf_ptr;
-       struct langwell_dtd     *dtd;
+       struct langwell_dtd     *dtd = NULL;
        struct langwell_udc     *dev;
        int                     i;
 
@@ -672,7 +702,9 @@ static struct langwell_dtd *build_dtd(struct langwell_request *req,
                        (unsigned)DTD_MAX_TRANSFER_LENGTH);
 
        /* create dTD dma_pool resource */
-       dtd = dma_pool_alloc(dev->dtd_pool, GFP_ATOMIC, dma);
+       if (dev->dtd_pool)
+               dtd = dma_pool_alloc(dev->dtd_pool, GFP_ATOMIC, dma);
+
        if (dtd == NULL)
                return dtd;
        dtd->dtd_dma = *dma;
@@ -767,7 +799,7 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
        struct langwell_ep      *ep;
        struct langwell_udc     *dev;
        unsigned long           flags;
-       int                     is_iso = 0, zlflag = 0;
+       int                     is_iso = 0, zlflag = 0, in = 0;
 
        /* always require a cpu-view buffer */
        req = container_of(_req, struct langwell_request, req);
@@ -785,11 +817,29 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
        req->ep = ep;
        dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
+       /* Put all accesses to ep->desc here.
+       *
+       * ep->desc can be disabled by interrupt handler
+       * ( i.e. ep->desc == NULL ) ,
+       * but it's safe to access ep->desc if we lock it first.
+       */
+       spin_lock_irqsave(&dev->lock, flags);
+       if (!ep->desc) {
+               spin_unlock_irqrestore(&dev->lock, flags);
+               dev_err(&dev->pdev->dev, "ep disabled while enqueuing a request\n");
+               return -EINVAL;
+       }
+
        if (usb_endpoint_xfer_isoc(ep->desc)) {
-               if (req->req.length > ep->ep.maxpacket)
+               if (req->req.length > ep->ep.maxpacket) {
+                       spin_unlock_irqrestore(&dev->lock, flags);
                        return -EMSGSIZE;
+               }
                is_iso = 1;
        }
+       in = is_in(ep);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
 
        if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
                return -ESHUTDOWN;
@@ -805,7 +855,7 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 
                _req->dma = dma_map_single(&dev->pdev->dev,
                                _req->buf, _req->length,
-                               is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                               in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
                if (zlflag && (_req->length == 1)) {
                        dev_vdbg(&dev->pdev->dev, "req->length: 1->0\n");
                        zlflag = 0;
@@ -817,7 +867,7 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
        } else {
                dma_sync_single_for_device(&dev->pdev->dev,
                                _req->dma, _req->length,
-                               is_in(ep) ?  DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                               in ?  DMA_TO_DEVICE : DMA_FROM_DEVICE);
                req->mapped = 0;
                dev_vdbg(&dev->pdev->dev, "req->mapped = 0\n");
        }
@@ -833,6 +883,16 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 
        spin_lock_irqsave(&dev->lock, flags);
 
+       /* Needs to check ep->desc again, ep might be disabled
+       * during lock is not held
+       */
+       if (!ep->desc) {
+               spin_unlock_irqrestore(&dev->lock, flags);
+               /* TODO:unmap req buffer if it was mapped */
+               dev_err(&dev->pdev->dev, "ep disabled while enqueuing a request\n");
+               return -EINVAL;
+       }
+
        /* build and put dTDs to endpoint queue */
        if (!req_to_dtd(req)) {
                queue_dtd(ep, req);
@@ -877,6 +937,8 @@ static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
        if (!dev->driver)
                return -ESHUTDOWN;
 
+       pm_runtime_get_sync(&dev->pdev->dev);
+
        spin_lock_irqsave(&dev->lock, flags);
        stopped = ep->stopped;
 
@@ -944,6 +1006,8 @@ done:
        ep->stopped = stopped;
        spin_unlock_irqrestore(&dev->lock, flags);
 
+       pm_runtime_put_sync(&dev->pdev->dev);
+
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
        return retval;
 }
@@ -987,7 +1051,7 @@ static void ep_set_halt(struct langwell_ep *ep, int value)
 
 
 /* set the endpoint halt feature */
-static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
+static int _langwell_ep_set_halt(struct usb_ep *_ep, int value, int chq)
 {
        struct langwell_ep      *ep;
        struct langwell_udc     *dev;
@@ -1008,13 +1072,15 @@ static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
        if (usb_endpoint_xfer_isoc(ep->desc))
                return  -EOPNOTSUPP;
 
+       pm_runtime_get_sync(&dev->pdev->dev);
+
        spin_lock_irqsave(&dev->lock, flags);
 
        /*
         * attempt to halt IN ep will fail if any transfer requests
         * are still queue
         */
-       if (!list_empty(&ep->queue) && is_in(ep) && value) {
+       if (chq && !list_empty(&ep->queue) && is_in(ep) && value) {
                /* IN endpoint FIFO holds bytes */
                dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name);
                retval = -EAGAIN;
@@ -1030,12 +1096,19 @@ static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
        }
 done:
        spin_unlock_irqrestore(&dev->lock, flags);
+
+       pm_runtime_put_sync(&dev->pdev->dev);
+
        dev_dbg(&dev->pdev->dev, "%s %s halt\n",
                        _ep->name, value ? "set" : "clear");
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
        return retval;
 }
 
+static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       return _langwell_ep_set_halt(_ep, value, 1);
+}
 
 /* set the halt feature and ignores clear requests */
 static int langwell_ep_set_wedge(struct usb_ep *_ep)
@@ -1055,6 +1128,34 @@ static int langwell_ep_set_wedge(struct usb_ep *_ep)
        return usb_ep_set_halt(_ep);
 }
 
+/* enter or exit PHY low power state */
+static void langwell_phy_low_power(struct langwell_udc *dev, bool flag)
+{
+       u32             devlc;
+       u8              devlc_byte2;
+       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
+
+       pm_runtime_get_sync(&dev->pdev->dev);
+       devlc = readl(&dev->op_regs->devlc);
+       dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
+
+       if (flag)
+               devlc |= LPM_PHCD;
+       else
+               devlc &= ~LPM_PHCD;
+
+       /* FIXME: workaround for Langwell A1/A2/A3 sighting */
+       devlc_byte2 = (devlc >> 16) & 0xff;
+       writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
+
+       devlc = readl(&dev->op_regs->devlc);
+       dev_vdbg(&dev->pdev->dev,
+                "%s PHY low power suspend, devlc = 0x%08x\n",
+                flag ? "enter" : "exit", devlc);
+
+       pm_runtime_put_sync(&dev->pdev->dev);
+}
+
 
 /* flush contents of a fifo */
 static void langwell_ep_fifo_flush(struct usb_ep *_ep)
@@ -1078,6 +1179,19 @@ static void langwell_ep_fifo_flush(struct usb_ep *_ep)
        dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n",
                        _ep->name, DIR_STRING(ep));
 
+       pm_runtime_get_sync(&dev->pdev->dev);
+
+       langwell_phy_low_power(dev, 0);
+       /* delay 3 millisecond to wait for phy exiting low power mode,
+          otherwise it easy to cause fabric error. the function can't use
+          msleep in here, because composite device will call this function with
+          holding spin lock. although it call pm_runtime_get_sync before which
+          would cause schedule too, but composite device would call
+          pm_runtime_get_sync prior to this function, so hereby it would
+          not cause schedule, just count plug one.
+       */
+       mdelay(3);
+
        /* flush endpoint buffer */
        if (ep->ep_num == 0)
                flush_bit = (1 << 16) | 1;
@@ -1099,6 +1213,8 @@ static void langwell_ep_fifo_flush(struct usb_ep *_ep)
                }
        } while (readl(&dev->op_regs->endptstat) & flush_bit);
 done:
+       pm_runtime_put_sync(&dev->pdev->dev);
+
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 }
 
@@ -1158,32 +1274,6 @@ static int langwell_get_frame(struct usb_gadget *_gadget)
 }
 
 
-/* enter or exit PHY low power state */
-static void langwell_phy_low_power(struct langwell_udc *dev, bool flag)
-{
-       u32             devlc;
-       u8              devlc_byte2;
-       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
-       devlc = readl(&dev->op_regs->devlc);
-       dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
-
-       if (flag)
-               devlc |= LPM_PHCD;
-       else
-               devlc &= ~LPM_PHCD;
-
-       /* FIXME: workaround for Langwell A1/A2/A3 sighting */
-       devlc_byte2 = (devlc >> 16) & 0xff;
-       writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
-
-       devlc = readl(&dev->op_regs->devlc);
-       dev_vdbg(&dev->pdev->dev,
-                       "%s PHY low power suspend, devlc = 0x%08x\n",
-                       flag ? "enter" : "exit", devlc);
-}
-
-
 /* tries to wake up the host connected to this gadget */
 static int langwell_wakeup(struct usb_gadget *_gadget)
 {
@@ -1302,6 +1392,10 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
 
        dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
+       pm_runtime_get_sync(&dev->pdev->dev);
+       /* PHY should exit low power before set USBCMD Run/Stop */
+       langwell_phy_low_power(dev, 0);
+
        spin_lock_irqsave(&dev->lock, flags);
        dev->softconnected = (is_on != 0);
 
@@ -1316,6 +1410,8 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
        }
        spin_unlock_irqrestore(&dev->lock, flags);
 
+       pm_runtime_put_sync(&dev->pdev->dev);
+
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
        return 0;
 }
@@ -1365,6 +1461,11 @@ static int langwell_udc_reset(struct langwell_udc *dev)
 
        dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
+       /* clear devlc's auto low power bit */
+       devlc = readl(&dev->op_regs->devlc);
+       devlc &= ~LPM_ASUS;
+       writel(devlc, &dev->op_regs->devlc);
+
        /* set controller to stop state */
        usbcmd = readl(&dev->op_regs->usbcmd);
        usbcmd &= ~CMD_RUNSTOP;
@@ -1507,6 +1608,24 @@ static void langwell_udc_start(struct langwell_udc *dev)
        dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 }
 
+/* disable test mode */
+static void langwell_udc_stop_testmode(struct langwell_udc *dev)
+{
+       u32     portsc1;
+
+       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
+
+       portsc1 = readl(&dev->op_regs->portsc1);
+
+       if (PORTS_PTC(portsc1)) {
+               dev_info(&dev->pdev->dev, "Exit USB Test mode\n");
+               portsc1 &= ~PORTS_PTC_MASK;
+               writel(portsc1, &dev->op_regs->portsc1);
+       }
+
+       dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+       return;
+}
 
 /* disable interrupt and set controller to stop state */
 static void langwell_udc_stop(struct langwell_udc *dev)
@@ -1862,6 +1981,8 @@ static int langwell_start(struct usb_gadget_driver *driver,
        driver->driver.bus = NULL;
        dev->driver = driver;
        dev->gadget.dev.driver = &driver->driver;
+       driver->ep_max = dev->ep_max;
+       driver->drv_state = REGISTERED;
 
        spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -1910,6 +2031,10 @@ static int langwell_stop(struct usb_gadget_driver *driver)
        if (unlikely(!driver || !driver->unbind || !driver->disconnect))
                return -EINVAL;
 
+#ifdef OTG_TRANSCEIVER
+       pm_runtime_get_sync(&dev->pdev->dev);
+#endif
+
        /* exit PHY low power suspend */
        langwell_phy_low_power(dev, 0);
 
@@ -1935,6 +2060,11 @@ static int langwell_stop(struct usb_gadget_driver *driver)
        driver->unbind(&dev->gadget);
        dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
+       driver->drv_state = UNREGISTERED;
+
+#ifdef OTG_TRANSCEIVER
+       pm_runtime_put_sync(&dev->pdev->dev);
+#endif
 
        dev_info(&dev->pdev->dev, "unregistered driver '%s'\n",
                        driver->driver.name);
@@ -2052,6 +2182,74 @@ static int prime_status_phase(struct langwell_udc *dev, int dir)
        return status;
 }
 
+static void test_mode_complete(struct usb_ep *ep, struct usb_request *_req)
+{
+       struct langwell_udc     *dev = the_controller;
+       struct langwell_request *req;
+       u32                     portsc1;
+
+       req = container_of(_req, struct langwell_request, req);
+
+       switch (req->test_mode) {
+       case TEST_J:
+       case TEST_K:
+       case TEST_SE0_NAK:
+       case TEST_PACKET:
+       case TEST_FORCE_EN:
+               portsc1 = readl(&dev->op_regs->portsc1);
+               portsc1 |= req->test_mode << 16;
+               writel(portsc1, &dev->op_regs->portsc1);
+               dev_info(&dev->pdev->dev,
+                       "Enter USB Test Mode 0x%x\n", req->test_mode);
+               break;
+       default:
+               dev_warn(&dev->pdev->dev, "unknown test mode\n");
+               break;
+       }
+}
+
+/* prime_status_phase_test_mode - PRIME a status phase for test mode request
+ */
+static int prime_status_phase_test_mode(struct langwell_udc *dev,
+                                               int dir, unsigned test_mode)
+{
+       struct langwell_request *req;
+       struct langwell_ep      *ep;
+       int                     status = 0;
+
+       dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
+
+       if (dir == EP_DIR_IN)
+               dev->ep0_dir = USB_DIR_IN;
+       else
+               dev->ep0_dir = USB_DIR_OUT;
+
+       ep = &dev->ep[0];
+       dev->ep0_state = WAIT_FOR_OUT_STATUS;
+
+       req = dev->status_req;
+
+       req->ep = ep;
+       req->test_mode = test_mode;
+       req->req.length = 0;
+       req->req.status = -EINPROGRESS;
+       req->req.actual = 0;
+       req->req.complete = test_mode_complete;
+       req->dtd_count = 0;
+
+       if (!req_to_dtd(req))
+               status = queue_dtd(ep, req);
+       else
+               return -ENOMEM;
+
+       if (status)
+               dev_err(&dev->pdev->dev, "can't queue ep0 status request\n");
+
+       list_add_tail(&req->queue, &ep->queue);
+
+       dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+       return status;
+}
 
 /* SET_ADDRESS request routine */
 static void set_address(struct langwell_udc *dev, u16 value,
@@ -2208,7 +2406,6 @@ static void handle_setup_packet(struct langwell_udc *dev,
        u16     wValue = le16_to_cpu(setup->wValue);
        u16     wIndex = le16_to_cpu(setup->wIndex);
        u16     wLength = le16_to_cpu(setup->wLength);
-       u32     portsc1;
 
        dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
@@ -2278,9 +2475,9 @@ static void handle_setup_packet(struct langwell_udc *dev,
                                break;
 
                        spin_unlock(&dev->lock);
-                       rc = langwell_ep_set_halt(&epn->ep,
+                       rc = _langwell_ep_set_halt(&epn->ep,
                                (setup->bRequest == USB_REQ_SET_FEATURE)
-                               ? 1 : 0);
+                               ? 1 : 0, 0);
                        spin_lock(&dev->lock);
 
                } else if ((setup->bRequestType & (USB_RECIP_MASK
@@ -2309,16 +2506,19 @@ static void handle_setup_packet(struct langwell_udc *dev,
                                case TEST_SE0_NAK:
                                case TEST_PACKET:
                                case TEST_FORCE_EN:
-                                       if (prime_status_phase(dev, EP_DIR_IN))
+                                       if (prime_status_phase_test_mode(dev,
+                                               EP_DIR_IN, wIndex >> 8))
                                                ep0_stall(dev);
-                                       portsc1 = readl(&dev->op_regs->portsc1);
-                                       portsc1 |= (wIndex & 0xf00) << 8;
-                                       writel(portsc1, &dev->op_regs->portsc1);
                                        goto end;
+                               case TEST_SRP_REQD:
+                                       langwell_udc_notify_otg(
+                                               MID_OTG_NOTIFY_TEST_SRP_REQD);
+                                       break;
                                default:
                                        rc = -EOPNOTSUPP;
                                }
                                break;
+                       case USB_DEVICE_B_HNP_ENABLE:
                                dev->gadget.b_hnp_enable = 1;
                                dev->dev_status |= (1 << wValue);
                                break;
@@ -2714,6 +2914,9 @@ static void handle_usb_reset(struct langwell_udc *dev)
 
        dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
+       /* notify reset event to OTG */
+       langwell_udc_notify_otg(MID_OTG_NOTIFY_CRESET);
+
        /* Write-Clear the device address */
        deviceaddr = readl(&dev->op_regs->deviceaddr);
        writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr);
@@ -2783,10 +2986,6 @@ static void handle_usb_reset(struct langwell_udc *dev)
                dev->usb_state = USB_STATE_ATTACHED;
        }
 
-       if (dev->iotg)
-               atomic_notifier_call_chain(&dev->iotg->iotg_notifier,
-                               MID_OTG_NOTIFY_CLIENTFS, dev->iotg);
-
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 }
 
@@ -2796,13 +2995,13 @@ static void handle_bus_suspend(struct langwell_udc *dev)
 {
        dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
+       if (dev->usb_state == USB_STATE_SUSPENDED)
+               return;
+
        dev->resume_state = dev->usb_state;
        dev->usb_state = USB_STATE_SUSPENDED;
 
-#ifdef OTG_TRANSCEIVER
-       atomic_notifier_call_chain(&dev->iotg->iotg_notifier,
-                               MID_OTG_NOTIFY_CSUSPEND, dev->iotg);
-#endif
+       langwell_udc_notify_otg(MID_OTG_NOTIFY_CSUSPEND);
 
        /* report suspend to the driver */
        if (dev->driver) {
@@ -2832,10 +3031,7 @@ static void handle_bus_resume(struct langwell_udc *dev)
        /* exit PHY low power suspend */
        langwell_phy_low_power(dev, 0);
 
-#ifdef OTG_TRANSCEIVER
-       atomic_notifier_call_chain(&dev->iotg->iotg_notifier,
-                               MID_OTG_NOTIFY_CRESUME, dev->iotg);
-#endif
+       langwell_udc_notify_otg(MID_OTG_NOTIFY_CRESUME);
 
        /* report resume to the driver */
        if (dev->driver) {
@@ -2968,6 +3164,8 @@ static void gadget_release(struct device *_dev)
 
        complete(dev->done);
 
+       wake_lock_destroy(&dev->wake_lock);
+
        dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
        kfree(dev);
 }
@@ -3049,6 +3247,8 @@ static void langwell_udc_remove(struct pci_dev *pdev)
        dev->done = &done;
 
 #ifndef        OTG_TRANSCEIVER
+       pm_runtime_get_noresume(&pdev->dev);
+
        /* free dTD dma_pool and dQH */
        if (dev->dtd_pool)
                dma_pool_destroy(dev->dtd_pool);
@@ -3155,6 +3355,12 @@ static int langwell_udc_probe(struct pci_dev *pdev,
        dev->iotg = otg_to_mid_xceiv(dev->transceiver);
 
        base = dev->iotg->base;
+
+       /*
+        * In OTG case, OTG Transceiver driver initialize itself early
+        * so if udc want to access hardware, just get_sync it back.
+        */
+       pm_runtime_get_sync(&dev->pdev->dev);
 #else
        pci_set_drvdata(pdev, dev);
 
@@ -3338,6 +3544,9 @@ static int langwell_udc_probe(struct pci_dev *pdev,
        }
 #endif
 
+       wake_lock_init(&dev->wake_lock, WAKE_LOCK_SUSPEND,
+                       pci_name(dev->pdev));
+
        /* done */
        dev_info(&dev->pdev->dev, "%s\n", driver_desc);
        dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base);
@@ -3372,6 +3581,12 @@ static int langwell_udc_probe(struct pci_dev *pdev,
        if (retval)
                goto error_attr1;
 
+#ifdef OTG_TRANSCEIVER
+       pm_runtime_put_sync(&pdev->dev);
+#else
+       pm_runtime_put_noidle(&pdev->dev);
+#endif
+
        dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
        return 0;
 
@@ -3412,11 +3627,6 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
        /* save PCI state */
        pci_save_state(pdev);
 
-       spin_lock_irq(&dev->lock);
-       /* stop all usb activities */
-       stop_activity(dev, dev->driver);
-       spin_unlock_irq(&dev->lock);
-
        /* free dTD dma_pool and dQH */
        if (dev->dtd_pool)
                dma_pool_destroy(dev->dtd_pool);
@@ -3520,6 +3730,66 @@ static int langwell_udc_resume(struct pci_dev *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+/* device controller runtime suspend */
+static int langwell_udc_runtime_suspend(struct device *device)
+{
+       struct langwell_udc     *dev = the_controller;
+       struct pci_dev          *pdev;
+
+       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
+
+       pdev = to_pci_dev(device);
+
+       /* save PCI state */
+       pci_save_state(pdev);
+
+       /* disable PCI device */
+       pci_disable_device(pdev);
+
+       /* set device power state */
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       dev->vbus_active = 0;
+
+       dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* device controller runtime resume */
+static int langwell_udc_runtime_resume(struct device *device)
+{
+       struct langwell_udc     *dev = the_controller;
+       struct pci_dev          *pdev;
+
+       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
+
+       pdev = to_pci_dev(device);
+
+       /* set device D0 power state */
+       pci_set_power_state(pdev, PCI_D0);
+
+       /* restore PCI state */
+       pci_restore_state(pdev);
+
+       /* enable PCI device */
+       if (pci_enable_device(pdev) < 0)
+               return -ENODEV;
+
+       dev->vbus_active = 1;
+
+       dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+#else
+
+#define langwell_udc_runtime_suspend NULL
+#define langwell_udc_runtime_resume NULL
+
+#endif
+
 
 /* pci driver shutdown */
 static void langwell_udc_shutdown(struct pci_dev *pdev)
@@ -3559,8 +3829,15 @@ static const struct pci_device_id pci_ids[] = { {
 
 MODULE_DEVICE_TABLE(pci, pci_ids);
 
+static const struct dev_pm_ops langwell_udc_pm_ops = {
+       .runtime_suspend = langwell_udc_runtime_suspend,
+       .runtime_resume = langwell_udc_runtime_resume,
+};
 
 static struct pci_driver langwell_pci_driver = {
+       .driver =       {
+               .pm = &langwell_udc_pm_ops,
+       },
        .name =         (char *) driver_name,
        .id_table =     pci_ids,
 
@@ -3578,18 +3855,77 @@ static struct pci_driver langwell_pci_driver = {
 static int intel_mid_start_peripheral(struct intel_mid_otg_xceiv *iotg)
 {
        struct langwell_udc     *dev = the_controller;
-       struct pci_dev          *pdev;
+       size_t                  size;
        unsigned long           flags;
-       int                     retval;
 
-       if (iotg == NULL)
-               return -EINVAL;
+       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
-       pdev = to_pci_dev(iotg->otg.dev);
+       wake_lock(&dev->wake_lock);
+       pm_runtime_get(&dev->pdev->dev);
 
-       retval = langwell_udc_resume(pdev);
-       if (retval)
-               dev_dbg(&pdev->dev, "Failed to start peripheral driver\n");
+       /* exit PHY low power suspend */
+       langwell_phy_low_power(dev, 0);
+
+       /* enable SRAM caching if detected */
+       if (dev->has_sram && !dev->got_sram)
+               sram_init(dev);
+
+       /* allocate device dQH memory */
+       size = dev->ep_max * sizeof(struct langwell_dqh);
+       dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size);
+       if (size < DQH_ALIGNMENT)
+               size = DQH_ALIGNMENT;
+       else if ((size % DQH_ALIGNMENT) != 0) {
+               size += DQH_ALIGNMENT + 1;
+               size &= ~(DQH_ALIGNMENT - 1);
+       }
+       dev->ep_dqh = dma_alloc_coherent(&dev->pdev->dev, size,
+                                       &dev->ep_dqh_dma, GFP_KERNEL);
+       if (!dev->ep_dqh) {
+               dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
+               return -ENOMEM;
+       }
+       dev->ep_dqh_size = size;
+       dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
+
+       /* create dTD dma_pool resource */
+       dev->dtd_pool = dma_pool_create("langwell_dtd",
+                       &dev->pdev->dev,
+                       sizeof(struct langwell_dtd),
+                       DTD_ALIGNMENT,
+                       DMA_BOUNDARY);
+
+       if (!dev->dtd_pool)
+               return -ENOMEM;
+
+       /* enable IRQ handler */
+       if (request_irq(dev->pdev->irq, langwell_irq, IRQF_SHARED,
+                               driver_name, dev) != 0) {
+               dev_err(&dev->pdev->dev, "request interrupt %d failed\n",
+                               dev->pdev->irq);
+               return -EBUSY;
+       }
+       dev->got_irq = 1;
+
+       if ((!dev->driver) || (dev->driver->drv_state != BIND_UNBIND)) {
+               /* reset and start controller to run state */
+               if (dev->stopped) {
+                       /* reset device controller */
+                       langwell_udc_reset(dev);
+
+                       /* reset ep0 dQH and endptctrl */
+                       ep0_reset(dev);
+
+                       /* start device if gadget is loaded */
+                       if (dev->driver)
+                               langwell_udc_start(dev);
+
+                       /* reset USB status */
+                       dev->usb_state = USB_STATE_ATTACHED;
+                       dev->ep0_state = WAIT_FOR_SETUP;
+                       dev->ep0_dir = USB_DIR_OUT;
+               }
+       }
 
        if (dev) {
                spin_lock_irqsave(&dev->lock, flags);
@@ -3597,24 +3933,46 @@ static int intel_mid_start_peripheral(struct intel_mid_otg_xceiv *iotg)
                spin_unlock_irqrestore(&dev->lock, flags);
        }
 
-       return retval;
+       dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+       return 0;
 }
 
 static int intel_mid_stop_peripheral(struct intel_mid_otg_xceiv *iotg)
 {
        struct langwell_udc     *dev = the_controller;
-       struct pci_dev          *pdev;
        unsigned long           flags;
-       int                     retval;
 
-       if (iotg == NULL)
-               return -EINVAL;
+       dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
-       pdev = to_pci_dev(iotg->otg.dev);
+       /* disable test mode */
+       langwell_udc_stop_testmode(dev);
 
-       retval = langwell_udc_suspend(pdev, PMSG_FREEZE);
-       if (retval)
-               dev_dbg(&pdev->dev, "Failed to stop peripheral driver\n");
+       /* disable interrupt and set controller to stop state */
+       langwell_udc_stop(dev);
+
+       /* diable IRQ handler */
+       if (dev->got_irq)
+               free_irq(dev->pdev->irq, dev);
+       dev->got_irq = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       /* stop all usb activities */
+       stop_activity(dev, dev->driver);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       /* free dTD dma_pool and dQH */
+       if (dev->dtd_pool) {
+               dma_pool_destroy(dev->dtd_pool);
+               dev->dtd_pool = NULL;
+       }
+
+       if (dev->ep_dqh)
+               dma_free_coherent(&dev->pdev->dev, dev->ep_dqh_size,
+                       dev->ep_dqh, dev->ep_dqh_dma);
+
+       /* release SRAM caching */
+       if (dev->has_sram && dev->got_sram)
+               sram_deinit(dev);
 
        if (dev) {
                spin_lock_irqsave(&dev->lock, flags);
@@ -3622,7 +3980,11 @@ static int intel_mid_stop_peripheral(struct intel_mid_otg_xceiv *iotg)
                spin_unlock_irqrestore(&dev->lock, flags);
        }
 
-       return retval;
+       pm_runtime_put(&dev->pdev->dev);
+       wake_unlock(&dev->wake_lock);
+
+       dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+       return 0;
 }
 
 static int intel_mid_register_peripheral(struct pci_driver *peripheral_driver)
@@ -3651,8 +4013,7 @@ static int intel_mid_register_peripheral(struct pci_driver *peripheral_driver)
        iotg->start_peripheral = intel_mid_start_peripheral;
        iotg->stop_peripheral = intel_mid_stop_peripheral;
 
-       atomic_notifier_call_chain(&iotg->iotg_notifier,
-                               MID_OTG_NOTIFY_CLIENTADD, iotg);
+       langwell_udc_notify_otg(MID_OTG_NOTIFY_CLIENTADD);
 
        otg_put_transceiver(otg);
 
index cf77d63..396f23f 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/usb/langwell_udc.h>
 #include <linux/usb/intel_mid_otg.h>
+#include <linux/wakelock.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -144,6 +145,7 @@ struct langwell_request {
        struct list_head        queue;
        unsigned                dtd_count;
        unsigned                mapped:1;
+       unsigned                test_mode;
 };
 
 
@@ -229,5 +231,7 @@ struct langwell_udc {
 
        /* device status data for get_status request */
        u16                     dev_status;
+
+       struct  wake_lock       wake_lock;
 };
 
index 4a702ce..0112e1f 100644 (file)
@@ -54,8 +54,8 @@ static const char driver_name[] = "penwell_otg";
 static int penwell_otg_probe(struct pci_dev *pdev,
                        const struct pci_device_id *id);
 static void penwell_otg_remove(struct pci_dev *pdev);
-static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message);
-static int penwell_otg_resume(struct pci_dev *pdev);
+static int penwell_otg_suspend(struct device *dev);
+static int penwell_otg_resume(struct device *pdev);
 
 static int penwell_otg_set_host(struct otg_transceiver *otg,
                                struct usb_bus *host);
@@ -107,6 +107,8 @@ static const char *charger_string(enum usb_charger_type charger)
                return "Charging Downstream Port";
        case CHRG_DCP:
                return "Dedicated Charging Port";
+       case CHRG_ACA:
+               return "Accessory Charger Adaptor";
        case CHRG_UNKNOWN:
                return "Unknown";
        default:
@@ -307,7 +309,7 @@ static int penwell_otg_set_power(struct otg_transceiver *otg,
        spin_lock_irqsave(&pnw->charger_lock, flags);
 
        if (pnw->charging_cap.chrg_type != CHRG_SDP) {
-               spin_unlock(&pnw->charger_lock);
+               spin_unlock_irqrestore(&pnw->charger_lock, flags);
                return 0;
        }
 
@@ -465,14 +467,14 @@ penwell_otg_ulpi_read(struct intel_mid_otg_xceiv *iotg, u8 reg, u8 *val)
        val32 = ULPI_RUN | reg << 16;
        writel(val32, pnw->iotg.base + CI_ULPIVP);
 
-       /* Polling for write operation to complete*/
-       count = 10;
+       /* Polling at least 1ms for read operation to complete*/
+       count = 200;
 
        while (count) {
                val32 = readl(pnw->iotg.base + CI_ULPIVP);
                if (val32 & ULPI_RUN) {
                        count--;
-                       udelay(20);
+                       udelay(5);
                } else {
                        *val = (u8)((val32 & ULPI_DATRD) >> 8);
                        dev_dbg(pnw->dev,
@@ -501,12 +503,12 @@ penwell_otg_ulpi_write(struct intel_mid_otg_xceiv *iotg, u8 reg, u8 val)
        val32 = ULPI_RUN | ULPI_RW | reg << 16 | val;
        writel(val32, pnw->iotg.base + CI_ULPIVP);
 
-       /* Polling for write operation to complete*/
-       count = 10;
+       /* Polling at least 1ms for write operation to complete*/
+       count = 200;
 
        while (count && penwell_otg_ulpi_run()) {
                count--;
-               udelay(20);
+               udelay(5);
        }
 
        dev_dbg(pnw->dev,
@@ -674,7 +676,7 @@ static void penwell_otg_loc_sof(int on)
        struct usb_hcd          *hcd;
        int                     err;
 
-       dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "suspend" : "resume");
+       dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "resume" : "suspend");
 
        hcd = bus_to_hcd(pnw->iotg.otg.host);
        if (on)
@@ -718,6 +720,31 @@ static void penwell_otg_phy_low_power(int on)
        dev_dbg(pnw->dev, "%s <---\n", __func__);
 }
 
+/*
+ * VBUS330 is the power rail to otg transceiver, set it into low power mode
+ * or normal mode according to pm state. Call this function when spi access
+ * to MSIC registers is enabled.
+ */
+static int penwell_otg_vusb330_low_power(int on)
+{
+       struct penwell_otg      *pnw = the_transceiver;
+       u8                      data;
+       int                     retval;
+
+       dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
+
+       if (on)
+               data = 0x5; /* Low power mode */
+       else
+               data = 0x7; /* Normal mode */
+
+       retval = penwell_otg_msic_write(MSIC_VUSB330CNT, data);
+
+       dev_dbg(pnw->dev, "%s <---\n", __func__);
+
+       return retval;
+}
+
 /* Enable/Disable OTG interrupt */
 static void penwell_otg_intr(int on)
 {
@@ -777,10 +804,8 @@ static int penwell_otg_msic_write(u16 addr, u8 data)
        int                     retval = 0;
 
        retval = intel_scu_ipc_iowrite8(addr, data);
-       if (retval) {
+       if (retval)
                dev_warn(pnw->dev, "Failed to write MSIC register %x\n", addr);
-               return retval;
-       }
 
        return retval;
 }
@@ -957,6 +982,196 @@ static int penwell_otg_charger_type_detect(void)
        return charger;
 }
 
+/* manual charger detection by ULPI access */
+static int penwell_otg_manual_charger_detection(void)
+{
+       struct penwell_otg              *pnw = the_transceiver;
+       struct intel_mid_otg_xceiv      *iotg;
+       int                             retval;
+       u8                              data, data1, data2;
+       unsigned long                   timeout, interval;
+
+       dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+       iotg = &pnw->iotg;
+
+       dev_info(pnw->dev, "USB charger detection start...\n");
+
+       /* config PHY for DCD
+        * - OPMODE/TERMSEL/XCVRSEL=01/0/01
+        * - enable DP/DM pulldowns (ensure RX's don't float) */
+
+       /* ulpi_write(0x0b, 0x06) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_OTGCTRLSET,
+                               DMPULLDOWN | DPPULLDOWN);
+       if (retval)
+               return retval;
+
+       /* ulpi_write(0x05, 0x09) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_FUNCTRLSET,
+                               OPMODE0 | XCVRSELECT0);
+       if (retval)
+               return retval;
+
+       /* ulpi_write(0x06, 0x16) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_FUNCTRLCLR,
+                               OPMODE1 | TERMSELECT | XCVRSELECT1);
+       if (retval)
+               return retval;
+
+       /* ulpi_write(0x0c, 0x02) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_OTGCTRLCLR, DPPULLDOWN);
+       if (retval)
+               return retval;
+
+       /* ulpi_write(0x3e, 0x01) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, SWCNTRL);
+       if (retval)
+               return retval;
+
+       /* ulpi_write(0x86, 0x40) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_VS3SET, CHGD_IDP_SRC);
+       if (retval)
+               return retval;
+
+       dev_info(pnw->dev, "charger detection DCD start...\n");
+
+       /* Check DCD result, use same polling parameter */
+       timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT);
+       interval = DATACON_INTERVAL * 1000; /* us */
+
+       while (!time_after(jiffies, timeout)) {
+               retval = penwell_otg_ulpi_read(iotg, ULPI_VS4, &data);
+               if (retval) {
+                       dev_warn(pnw->dev, "Failed to read ULPI register\n");
+                       return retval;
+               }
+
+               if (data & !CHRG_SERX_DP) {
+                       dev_info(pnw->dev, "Data contact detected!\n");
+                       break;
+               }
+
+               /* Polling interval */
+               usleep_range(interval, interval + 2000);
+       }
+
+       /* ulpi_write(0x87, 0x40)*/
+       retval = penwell_otg_ulpi_write(iotg, ULPI_VS3CLR, CHGD_IDP_SRC);
+       if (retval)
+               return retval;
+
+       dev_info(pnw->dev, "DCD complete\n");
+       dev_info(pnw->dev, "Primary Detection start...\n");
+
+       /* Primary Dection config */
+       /* ulpi_write(0x0b, 0x06) */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_OTGCTRLSET,
+                               DMPULLDOWN | DPPULLDOWN);
+       if (retval)
+               return retval;
+
+       retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, DPVSRCEN);
+       if (retval)
+               return retval;
+
+       msleep(125);
+
+       /* Check result SDP vs CDP/DCP */
+       retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &data1);
+       if (retval)
+               return retval;
+
+       data1 = data1 & VDATDET;
+
+       retval = penwell_otg_ulpi_read(iotg, ULPI_VS4, &data2);
+       if (retval)
+               return retval;
+
+       data2 = data2 & CHRG_SERX_DM;
+
+       if (!data1 || data2) {
+               retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR,
+                                               DPVSRCEN);
+               if (retval)
+                       return retval;
+
+               dev_info(pnw->dev, "USB Charger Detection done\n");
+               return CHRG_SDP;
+       }
+
+       /* start detection on CDP vs DCP */
+       retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, DPVSRCEN);
+       if (retval)
+               return retval;
+
+       /* sleep 1ms between Primary and Secondary detection */
+       usleep_range(1000, 1200);
+
+       retval = penwell_otg_ulpi_write(iotg, ULPI_VS1CLR, DATAPOLARITY);
+       if (retval)
+               return retval;
+
+       retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, DPVSRCEN);
+       if (retval)
+               return retval;
+
+       msleep(85);
+
+       /* read result on CDP vs DCP */
+       retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &data);
+       if (retval)
+               return retval;
+
+       data = data & VDATDET;
+
+       retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, DPVSRCEN);
+       if (retval)
+               return retval;
+
+       retval = penwell_otg_ulpi_write(iotg, ULPI_VS1SET, DATAPOLARITY);
+       if (retval)
+               return retval;
+
+       dev_info(pnw->dev, "USB Charger Detection done\n");
+
+       if (data) {
+               retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET,
+                                                       DPVSRCEN);
+               if (retval)
+                       return retval;
+
+               return CHRG_DCP;
+       } else
+               return CHRG_CDP;
+
+       dev_dbg(pnw->dev, "%s <---\n", __func__);
+};
+
+void penwell_otg_phy_vbus_wakeup(bool on)
+{
+       struct penwell_otg      *pnw = the_transceiver;
+       u8                      flag = 0;
+
+       dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+       penwell_otg_msic_spi_access(true);
+
+       flag = VBUSVLD | SESSVLD | SESSEND;
+
+       if (on) {
+               penwell_otg_msic_write(MSIC_USBINTEN_RISESET, flag);
+               penwell_otg_msic_write(MSIC_USBINTEN_FALLSET, flag);
+       } else {
+               penwell_otg_msic_write(MSIC_USBINTEN_RISECLR, flag);
+               penwell_otg_msic_write(MSIC_USBINTEN_FALLCLR, flag);
+       }
+
+       penwell_otg_msic_spi_access(false);
+
+       dev_dbg(pnw->dev, "%s --->\n", __func__);
+}
+
 void penwell_otg_nsf_msg(unsigned long indicator)
 {
        switch (indicator) {
@@ -1053,6 +1268,21 @@ static void penwell_otg_add_timer(enum penwell_otg_timer_type timers)
                dev_dbg(pnw->dev,
                        "Add timer TB_SRP_FAIL = %d\n", TB_SRP_FAIL);
                break;
+       /* support OTG test mode */
+       case TTST_MAINT_TMR:
+               iotg->hsm.tst_maint_tmout = 0;
+               data = (unsigned long)&iotg->hsm.tst_maint_tmout;
+               time = TTST_MAINT;
+               dev_dbg(pnw->dev,
+                       "Add timer TTST_MAINT = %d\n", TTST_MAINT);
+               break;
+       case TTST_NOADP_TMR:
+               iotg->hsm.tst_noadp_tmout = 0;
+               data = (unsigned long)&iotg->hsm.tst_noadp_tmout;
+               time = TTST_NOADP;
+               dev_dbg(pnw->dev,
+                       "Add timer TTST_NOADP = %d\n", TTST_NOADP);
+               break;
        default:
                dev_dbg(pnw->dev,
                        "unkown timer, can not enable such timer\n");
@@ -1078,6 +1308,15 @@ static inline void penwell_otg_del_timer(enum penwell_otg_timer_type timers)
        case TB_SRP_FAIL_TMR:
                iotg->hsm.b_srp_fail_tmr = 0;
                break;
+       case TA_WAIT_BCON_TMR:
+               iotg->hsm.a_wait_bcon_tmout = 0;
+               break;
+       case TTST_MAINT_TMR:
+               iotg->hsm.tst_maint_tmout = 0;
+               break;
+       case TTST_NOADP_TMR:
+               iotg->hsm.tst_noadp_tmout = 0;
+               break;
        default:
                break;
        }
@@ -1163,7 +1402,7 @@ static void init_hsm(void)
        iotg->hsm.a_bus_req = 1;
        iotg->hsm.a_bus_drop = 0;
        /* init hsm means power_up case */
-       iotg->hsm.power_up = 1;
+       iotg->hsm.power_up = 0;
        /* defautly don't request bus as B device */
        iotg->hsm.b_bus_req = 0;
        /* no system error */
@@ -1220,10 +1459,9 @@ static irqreturn_t otg_dummy_irq(int irq, void *_dev)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t otg_irq(int irq, void *_dev)
+static irqreturn_t otg_irq_handle(struct penwell_otg *pnw,
+                                       struct intel_mid_otg_xceiv *iotg)
 {
-       struct penwell_otg              *pnw = _dev;
-       struct intel_mid_otg_xceiv      *iotg = &pnw->iotg;
        int                             flag = 0;
        u32                             int_sts, int_en, int_mask = 0;
 
@@ -1287,11 +1525,104 @@ static irqreturn_t otg_irq(int irq, void *_dev)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t otg_irq(int irq, void *_dev)
+{
+       struct penwell_otg              *pnw = _dev;
+       struct intel_mid_otg_xceiv      *iotg = &pnw->iotg;
+
+#ifdef CONFIG_PM_RUNTIME
+       if (pnw->rt_resuming) {
+               pnw->rt_resuming++;
+               return IRQ_HANDLED;
+       } else if (pnw->dev->power.runtime_status == RPM_RESUMING)
+               return IRQ_HANDLED;
+
+       /* If it's not active, resume device first before access regs */
+       if (pnw->dev->power.runtime_status != RPM_ACTIVE) {
+               dev_dbg(pnw->dev, "Wake up? Interrupt detected in suspended\n");
+               pnw->rt_resuming = 1;
+
+               pm_runtime_get(pnw->dev);
+
+               return IRQ_HANDLED;
+       }
+#endif /* CONFIG_PM_RUNTIME */
+
+       return otg_irq_handle(pnw, iotg);
+}
+
+static void penwell_otg_check_wakeup_event(struct penwell_otg *pnw)
+{
+       u32             int_sts, int_en, int_mask = 0;
+       int             flag = 0;
+       int             id, a_vbus_vld, b_sess_end;
+       int             b_sess_vld, a_sess_vld;
+
+       pnw = the_transceiver;
+
+       /* OTGSC needs 1ms debounce time to get synced with MSIC
+        * after back from clock gated state to D0, sleep 2ms
+        * will be enough */
+       usleep_range(1800, 2000);
+
+       /* Check VBUS/SRP interrup */
+       int_sts = readl(pnw->iotg.base + CI_OTGSC);
+       int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
+       int_mask = int_sts & int_en;
+
+       /* won't use OTGSC INTSTS bit, because controller is
+        * reset during runtime suspend, just check current status */
+
+       /* get current id/a_vbus_vld/b_sess_end/b_sess_vld/a_sess_vld */
+       id = !!(int_sts & OTGSC_ID) ? ID_B : ID_A;
+       b_sess_end = !!(int_sts & OTGSC_BSE);
+       b_sess_vld = !!(int_sts & OTGSC_BSV);
+       a_sess_vld = !!(int_sts & OTGSC_ASV);
+       a_vbus_vld = !!(int_sts & OTGSC_AVV);
+
+       if (id != pnw->iotg.hsm.id) {
+               pnw->iotg.hsm.id = id;
+               dev_dbg(pnw->dev, "ID Wake up id = %d\n", id);
+               flag = 1;
+       }
+
+       if (b_sess_end != pnw->iotg.hsm.b_sess_end) {
+               pnw->iotg.hsm.b_sess_end = b_sess_end;
+               dev_dbg(pnw->dev, "B_sess_end Wake up = %d\n", b_sess_end);
+               flag = 1;
+       }
+
+       if (b_sess_vld != pnw->iotg.hsm.b_sess_vld) {
+               pnw->iotg.hsm.b_sess_vld = b_sess_vld;
+               dev_dbg(pnw->dev, "B_sess_vld Wake up = %d\n", b_sess_vld);
+               flag = 1;
+       }
+
+       if (a_sess_vld != pnw->iotg.hsm.a_sess_vld) {
+               pnw->iotg.hsm.a_sess_vld = a_sess_vld;
+               dev_dbg(pnw->dev, "A_sess_vld Wake up = %d\n", a_sess_vld);
+               flag = 1;
+       }
+
+       if (a_vbus_vld != pnw->iotg.hsm.a_vbus_vld) {
+               pnw->iotg.hsm.a_vbus_vld = a_vbus_vld;
+               dev_dbg(pnw->dev, "A_vbus_vld Wake up = %d\n", a_vbus_vld);
+               flag = 1;
+       }
+
+       if (int_mask)
+               writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
+                               pnw->iotg.base + CI_OTGSC);
+       if (flag)
+               penwell_update_transceiver();
+}
+
 static int penwell_otg_iotg_notify(struct notifier_block *nb,
                                unsigned long action, void *data)
 {
        struct penwell_otg              *pnw = the_transceiver;
        struct intel_mid_otg_xceiv      *iotg = data;
+       unsigned long                   flags;
        int                             flag = 0;
 
        if (iotg == NULL)
@@ -1319,17 +1650,13 @@ static int penwell_otg_iotg_notify(struct notifier_block *nb,
                break;
        case MID_OTG_NOTIFY_HSUSPEND:
                dev_dbg(pnw->dev, "PNW OTG Notify Host Bus suspend Event\n");
-               if (iotg->otg.default_a == 1)
-                       iotg->hsm.a_bus_req = 0;
-               else
-                       iotg->hsm.b_bus_req = 0;
-               flag = 1;
                break;
        case MID_OTG_NOTIFY_HRESUME:
                dev_dbg(pnw->dev, "PNW OTG Notify Host Bus resume Event\n");
-               if (iotg->otg.default_a == 1)
+               if (iotg->otg.default_a == 1 && iotg->hsm.a_bus_req == 0) {
                        iotg->hsm.a_bus_req = 1;
-               flag = 1;
+                       flag = 1;
+               }
                break;
        case MID_OTG_NOTIFY_CSUSPEND:
                dev_dbg(pnw->dev, "PNW OTG Notify Client Bus suspend Event\n");
@@ -1356,6 +1683,11 @@ static int penwell_otg_iotg_notify(struct notifier_block *nb,
                        flag = 0;
                }
                break;
+       case MID_OTG_NOTIFY_CRESET:
+               dev_dbg(pnw->dev, "PNW OTG Notify Client Bus reset Event\n");
+               penwell_otg_set_power(&pnw->iotg.otg, CHRG_CURR_SDP_SUSP);
+               flag = 0;
+               break;
        case MID_OTG_NOTIFY_HOSTADD:
                dev_dbg(pnw->dev, "PNW OTG Nofity Host Driver Add\n");
                flag = 1;
@@ -1382,18 +1714,36 @@ static int penwell_otg_iotg_notify(struct notifier_block *nb,
                penwell_otg_update_chrg_cap(CHRG_CDP, CHRG_CURR_CDP_HS);
                flag = 0;
                break;
+       /* Test mode support */
+       case MID_OTG_NOTIFY_TEST_SRP_REQD:
+               dev_dbg(pnw->dev, "PNW OTG Notfiy Client SRP REQD\n");
+               iotg->hsm.otg_srp_reqd = 1;
+               flag = 1;
+               break;
+       case MID_OTG_NOTIFY_TEST:
+               dev_dbg(pnw->dev, "PNW OTG Notfiy Test device detected\n");
+               iotg->hsm.test_device = 1;
+               flag = 0;
+               break;
+       case MID_OTG_NOTIFY_TEST_VBUS_OFF:
+               dev_dbg(pnw->dev, "PNW OTG Notfiy Test device Vbus off mode\n");
+               iotg->hsm.test_device = 1;
+               iotg->hsm.otg_vbus_off = 1;
+               flag = 1;
+               break;
        default:
                dev_dbg(pnw->dev, "PNW OTG Nofity unknown notify message\n");
                return NOTIFY_DONE;
        }
 
-       if (flag)
+       spin_lock_irqsave(&pnw->notify_lock, flags);
+       if (flag && pnw->queue_stop == 0)
                penwell_update_transceiver();
+       spin_unlock_irqrestore(&pnw->notify_lock, flags);
 
        return NOTIFY_OK;
 }
 
-
 static void penwell_otg_hnp_poll_work(struct work_struct *work)
 {
        struct penwell_otg              *pnw = the_transceiver;
@@ -1458,6 +1808,7 @@ static void penwell_otg_work(struct work_struct *work)
        enum usb_charger_type           charger_type;
        int                             retval;
        struct pci_dev                  *pdev;
+       unsigned long                   flags;
 
        dev_dbg(pnw->dev,
                "old state = %s\n", state_string(iotg->otg.state));
@@ -1524,11 +1875,15 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Start USB Battery charger detection flow */
 
                        mutex_lock(&pnw->msic_mutex);
-                       /* Enable data contact detection */
-                       penwell_otg_data_contact_detect();
-                       /* Enable charger detection functionality */
-                       penwell_otg_charger_detect();
-                       retval = penwell_otg_charger_type_detect();
+                       if (pdev->revision >= 0x8) {
+                               retval = penwell_otg_manual_charger_detection();
+                       } else {
+                               /* Enable data contact detection */
+                               penwell_otg_data_contact_detect();
+                               /* Enable charger detection functionality */
+                               penwell_otg_charger_detect();
+                               retval = penwell_otg_charger_type_detect();
+                       }
                        mutex_unlock(&pnw->msic_mutex);
                        if (retval < 0) {
                                dev_warn(pnw->dev, "Charger detect failure\n");
@@ -1542,6 +1897,7 @@ static void penwell_otg_work(struct work_struct *work)
                                /* DCP: set charger type, current, notify EM */
                                penwell_otg_update_chrg_cap(CHRG_DCP,
                                                        CHRG_CURR_DCP);
+                               set_client_mode();
                                penwell_otg_phy_low_power(1);
                                break;
 
@@ -1574,6 +1930,9 @@ static void penwell_otg_work(struct work_struct *work)
                                if (iotg->otg.gadget)
                                        iotg->otg.gadget->host_request_flag = 0;
 
+                               penwell_otg_phy_low_power(0);
+                               set_client_mode();
+
                                if (iotg->start_peripheral) {
                                        iotg->start_peripheral(iotg);
                                } else {
@@ -1592,8 +1951,8 @@ static void penwell_otg_work(struct work_struct *work)
 
                        iotg->otg.state = OTG_STATE_B_PERIPHERAL;
 
-               } else if ((hsm->b_bus_req || hsm->power_up ||
-                               hsm->adp_change) && !hsm->b_srp_fail_tmr) {
+               } else if ((hsm->b_bus_req || hsm->power_up || hsm->adp_change
+                               || hsm->otg_srp_reqd) && !hsm->b_srp_fail_tmr) {
 
                        penwell_otg_mon_bus();
 
@@ -1617,10 +1976,27 @@ static void penwell_otg_work(struct work_struct *work)
                                dev_info(pnw->dev,
                                        "BUS is active, try SRP later\n");
                        }
+
+                       /* clear after SRP attemp */
+                       if (hsm->otg_srp_reqd) {
+                               dev_dbg(pnw->dev, "Test mode: SRP done\n");
+                               hsm->otg_srp_reqd = 0;
+                       }
                } else if (!hsm->b_sess_vld && hsm->id == ID_B) {
-                       /* Notify EM charger remove event */
-                       penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
+                       spin_lock_irqsave(&pnw->charger_lock, flags);
+                       charger_type = pnw->charging_cap.chrg_type;
+                       spin_unlock_irqrestore(&pnw->charger_lock, flags);
+
+                       if (charger_type == CHRG_DCP) {
+                               /* Notify EM charger remove event */
+                               penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
                                                CHRG_CURR_DISCONN);
+
+                               retval = penwell_otg_ulpi_write(iotg,
+                                               ULPI_PWRCTRLCLR, DPVSRCEN);
+                               if (retval)
+                                       dev_warn(pnw->dev, "ulpi failed\n");
+                       }
                }
                break;
 
@@ -1656,14 +2032,14 @@ static void penwell_otg_work(struct work_struct *work)
                                                        CHRG_CURR_DISCONN);
                        }
 
+                       hsm->b_bus_req = 0;
+
                        if (iotg->stop_peripheral)
                                iotg->stop_peripheral(iotg);
                        else
                                dev_dbg(pnw->dev,
                                        "client driver has been removed.\n");
 
-                       penwell_otg_phy_low_power(1);
-
                        iotg->otg.state = OTG_STATE_B_IDLE;
                } else if (hsm->b_bus_req && hsm->a_bus_suspend
                                && iotg->otg.gadget
@@ -1893,6 +2269,8 @@ static void penwell_otg_work(struct work_struct *work)
                                penwell_otg_update_chrg_cap(CHRG_ACA,
                                                        CHRG_CURR_ACA);
 
+                       hsm->b_bus_req = 0;
+
                        set_client_mode();
                        msleep(5);
                        penwell_otg_phy_low_power(1);
@@ -1932,12 +2310,16 @@ static void penwell_otg_work(struct work_struct *work)
                        if (hsm->adp_change)
                                hsm->adp_change = 0;
 
-                       if (hsm->a_srp_det)
+                       if (hsm->a_srp_det) {
                                hsm->a_srp_det = 0;
+                               /* wait SRP done, then enable VBUS */
+                               usleep_range(10000, 11000);
+                       }
 
                        if (iotg->otg.set_vbus)
                                iotg->otg.set_vbus(&iotg->otg, true);
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VRISE_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VRISE;
 
@@ -1963,6 +2345,7 @@ static void penwell_otg_work(struct work_struct *work)
                        if (iotg->otg.set_vbus)
                                iotg->otg.set_vbus(&iotg->otg, false);
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
                } else if (hsm->a_vbus_vld || hsm->a_wait_vrise_tmout
@@ -1975,6 +2358,8 @@ static void penwell_otg_work(struct work_struct *work)
                                /* Turn off VBUS */
                                if (iotg->otg.set_vbus)
                                        iotg->otg.set_vbus(&iotg->otg, false);
+
+                               pm_runtime_get(pnw->dev);
                                penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                                iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
                                break;
@@ -2000,11 +2385,14 @@ static void penwell_otg_work(struct work_struct *work)
                                break;
                        }
 
+                       pm_runtime_put(pnw->dev);
+                       penwell_otg_add_timer(TA_WAIT_BCON_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_BCON;
                }
                break;
        case OTG_STATE_A_WAIT_BCON:
-               if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop) {
+               if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop ||
+                       hsm->a_wait_bcon_tmout) {
                        /* Move to A_WAIT_VFALL state, user request */
 
                        /* Delete current timer and clear flags for B-Device */
@@ -2022,6 +2410,7 @@ static void penwell_otg_work(struct work_struct *work)
                        if (iotg->otg.set_vbus)
                                iotg->otg.set_vbus(&iotg->otg, false);
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
                } else if (!hsm->a_vbus_vld) {
@@ -2051,10 +2440,13 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Start HNP polling */
                        iotg->start_hnp_poll(iotg);
 
-                       iotg->otg.state = OTG_STATE_A_HOST;
-
                        if (!hsm->a_bus_req)
                                hsm->a_bus_req = 1;
+
+                       if (hsm->test_device)
+                               penwell_otg_add_timer(TTST_MAINT_TMR);
+
+                       iotg->otg.state = OTG_STATE_A_HOST;
                } else if (hsm->id == ID_ACA_A) {
                        penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
 
@@ -2067,6 +2459,13 @@ static void penwell_otg_work(struct work_struct *work)
        case OTG_STATE_A_HOST:
                if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop) {
                        /* Move to A_WAIT_VFALL state, timeout/user request */
+
+                       /* Delete current timer and clear flags */
+                       if (hsm->test_device) {
+                               hsm->test_device = 0;
+                               penwell_otg_del_timer(TTST_MAINT_TMR);
+                       }
+
                        if (hsm->id == ID_ACA_B)
                                penwell_otg_update_chrg_cap(CHRG_ACA,
                                                        CHRG_CURR_ACA);
@@ -2086,11 +2485,41 @@ static void penwell_otg_work(struct work_struct *work)
                        if (iotg->otg.set_vbus)
                                iotg->otg.set_vbus(&iotg->otg, false);
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
+               } else if (hsm->test_device && hsm->tst_maint_tmout) {
+
+                       hsm->test_device = 0;
+
+                       /* Stop HNP polling */
+                       iotg->stop_hnp_poll(iotg);
+
+                       penwell_otg_phy_low_power(0);
+
+                       if (iotg->stop_host)
+                               iotg->stop_host(iotg);
+                       else
+                               dev_dbg(pnw->dev,
+                                       "host driver has been removed.\n");
+
+                       /* Turn off VBUS */
+                       if (iotg->otg.set_vbus)
+                               iotg->otg.set_vbus(&iotg->otg, false);
+
+                       /* Clear states and wait for SRP */
+                       hsm->a_srp_det = 0;
+                       hsm->a_bus_req = 0;
+                       iotg->otg.state = OTG_STATE_A_IDLE;
                } else if (!hsm->a_vbus_vld) {
                        /* Move to A_VBUS_ERR state */
 
+                       /* Delete current timer and clear flags */
+                       if (hsm->test_device) {
+                               hsm->test_device = 0;
+                               penwell_otg_del_timer(TTST_MAINT_TMR);
+                       }
+
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
@@ -2106,38 +2535,70 @@ static void penwell_otg_work(struct work_struct *work)
 
                        penwell_otg_phy_low_power(1);
                        iotg->otg.state = OTG_STATE_A_VBUS_ERR;
-               } else if (!hsm->a_bus_req) {
+               } else if (!hsm->a_bus_req && iotg->otg.host->b_hnp_enable) {
                        /* Move to A_SUSPEND state */
 
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
-                       if (iotg->otg.host->b_hnp_enable) {
-                               /* According to Spec 7.1.5 */
-                               penwell_otg_add_timer(TA_AIDL_BDIS_TMR);
-
-                               /* Set HABA to enable hardware assistance to
-                                * signal A-connect after receiver B-disconnect
-                                * Hardware will then set client mode and
-                                * enable URE, SLE and PCE after the assistance
-                                * otg_dummy_irq is used to clean these ints
-                                * when client driver is not resumed.
-                                */
-                               if (request_irq(pdev->irq, otg_dummy_irq,
-                                               IRQF_SHARED, driver_name,
-                                                       iotg->base) != 0) {
+                       /* According to Spec 7.1.5 */
+                       penwell_otg_add_timer(TA_AIDL_BDIS_TMR);
+
+                       /* Set HABA to enable hardware assistance to
+                        * signal A-connect after receiver B-disconnect
+                        * Hardware will then set client mode and
+                        * enable URE, SLE and PCE after the assistance
+                        * otg_dummy_irq is used to clean these ints
+                        * when client driver is not resumed.
+                        */
+                       if (request_irq(pdev->irq, otg_dummy_irq,
+                                       IRQF_SHARED, driver_name,
+                                       iotg->base) != 0) {
                                        dev_dbg(pnw->dev,
-                                               "request interrupt %d failed\n",
-                                                               pdev->irq);
-                               }
-                               penwell_otg_HABA(1);
+                                       "request interrupt %d failed\n",
+                                       pdev->irq);
                        }
+                       penwell_otg_HABA(1);
 
                        penwell_otg_loc_sof(0);
                        penwell_otg_phy_low_power(0);
 
                        iotg->otg.state = OTG_STATE_A_SUSPEND;
+               } else if (!hsm->b_conn && hsm->test_device
+                                               && hsm->otg_vbus_off) {
+                       /* If it is a test device with otg_vbus_off bit set,
+                        * turn off VBUS on disconnect event and stay for
+                        * TTST_NOADP without ADP */
+
+                       penwell_otg_del_timer(TTST_MAINT_TMR);
+
+                       /* Stop HNP polling */
+                       iotg->stop_hnp_poll(iotg);
+
+                       penwell_otg_phy_low_power(0);
+
+                       if (iotg->stop_host)
+                               iotg->stop_host(iotg);
+                       else
+                               dev_dbg(pnw->dev,
+                                       "host driver has been removed.\n");
+
+                       /* Turn off VBUS */
+                       if (iotg->otg.set_vbus)
+                               iotg->otg.set_vbus(&iotg->otg, false);
+
+                       pm_runtime_get(pnw->dev);
+                       penwell_otg_add_timer(TTST_NOADP_TMR);
+                       iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
+
                } else if (!hsm->b_conn) {
+
+                       /* Delete current timer and clear flags */
+                       if (hsm->test_device) {
+                               hsm->test_device = 0;
+                               penwell_otg_del_timer(TTST_MAINT_TMR);
+                       }
+
                        /* Stop HNP polling */
                        iotg->stop_hnp_poll(iotg);
 
@@ -2181,6 +2642,7 @@ static void penwell_otg_work(struct work_struct *work)
                        if (iotg->otg.set_vbus)
                                iotg->otg.set_vbus(&iotg->otg, false);
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
                } else if (!hsm->a_vbus_vld) {
@@ -2204,8 +2666,6 @@ static void penwell_otg_work(struct work_struct *work)
                        iotg->otg.state = OTG_STATE_A_VBUS_ERR;
                } else if (!hsm->b_conn && !pnw->iotg.otg.host->b_hnp_enable) {
                        /* Move to A_WAIT_BCON */
-                       penwell_otg_HABA(0);
-                       free_irq(pdev->irq, iotg->base);
 
                        /* delete current timer */
                        penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
@@ -2285,6 +2745,7 @@ static void penwell_otg_work(struct work_struct *work)
                                iotg->otg.set_vbus(&iotg->otg, false);
                        set_host_mode();
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
                } else if (!hsm->a_vbus_vld) {
@@ -2352,6 +2813,7 @@ static void penwell_otg_work(struct work_struct *work)
                        if (hsm->a_clr_err)
                                hsm->a_clr_err = 0;
 
+                       pm_runtime_get(pnw->dev);
                        penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
                        iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
                }
@@ -2359,6 +2821,7 @@ static void penwell_otg_work(struct work_struct *work)
        case OTG_STATE_A_WAIT_VFALL:
                if (hsm->a_wait_vfall_tmout) {
                        hsm->a_srp_det = 0;
+                       hsm->a_wait_vfall_tmout = 0;
 
                        /* Move to A_IDLE state, vbus falls */
                        penwell_otg_phy_low_power(1);
@@ -2366,6 +2829,21 @@ static void penwell_otg_work(struct work_struct *work)
                        /* Always set a_bus_req to 1, in case no ADP */
                        hsm->a_bus_req = 1;
 
+                       pm_runtime_put(pnw->dev);
+                       iotg->otg.state = OTG_STATE_A_IDLE;
+                       penwell_update_transceiver();
+               } else if (hsm->test_device && hsm->otg_vbus_off
+                                       && hsm->tst_noadp_tmout) {
+                       /* After noadp timeout, switch back to normal mode */
+                       hsm->test_device = 0;
+                       hsm->otg_vbus_off = 0;
+                       hsm->tst_noadp_tmout = 0;
+
+                       penwell_otg_phy_low_power(1);
+
+                       hsm->a_bus_req = 1;
+
+                       pm_runtime_put(pnw->dev);
                        iotg->otg.state = OTG_STATE_A_IDLE;
                        penwell_update_transceiver();
                }
@@ -2391,6 +2869,8 @@ show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
        next = buf;
        size = PAGE_SIZE;
 
+       pm_runtime_get_sync(pnw->dev);
+
        t = scnprintf(next, size,
                "\n"
                "USBCMD = 0x%08x\n"
@@ -2410,6 +2890,9 @@ show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
                readl(pnw->iotg.base + 0xf4),
                readl(pnw->iotg.base + 0xf8)
                );
+
+       pm_runtime_put_sync(pnw->dev);
+
        size -= t;
        next += t;
 
@@ -2467,6 +2950,8 @@ show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
                "b_srp_fail_tmout = \t%d\n"
                "b_srp_fail_tmr = \t%d\n"
                "b_adp_sense_tmout = \t%d\n"
+               "tst_maint_tmout = \t%d\n"
+               "tst_noadp_tmout = \t%d\n"
                "a_bus_drop = \t%d\n"
                "a_bus_req = \t%d\n"
                "a_clr_err = \t%d\n"
@@ -2502,6 +2987,8 @@ show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
                iotg->hsm.b_srp_fail_tmout,
                iotg->hsm.b_srp_fail_tmr,
                iotg->hsm.b_adp_sense_tmout,
+               iotg->hsm.tst_maint_tmout,
+               iotg->hsm.tst_noadp_tmout,
                iotg->hsm.a_bus_drop,
                iotg->hsm.a_bus_req,
                iotg->hsm.a_clr_err,
@@ -2742,6 +3229,31 @@ static struct attribute_group debug_dev_attr_group = {
        .attrs = inputs_attrs,
 };
 
+static int penwell_otg_aca_enable(void)
+{
+       int                     retval = 0;
+       struct penwell_otg      *pnw = the_transceiver;
+
+       penwell_otg_msic_spi_access(true);
+
+       retval = intel_scu_ipc_update_register(SPI_TI_VS4,
+               TI_ACA_DET_EN, TI_ACA_DET_EN);
+       if (retval)
+               goto done;
+
+       retval = intel_scu_ipc_update_register(SPI_TI_VS5,
+               TI_ID_FLOAT_EN | TI_ID_RES_EN,
+               TI_ID_FLOAT_EN | TI_ID_RES_EN);
+
+done:
+       penwell_otg_msic_spi_access(false);
+
+       if (retval)
+               dev_warn(pnw->dev, "Failed to enable ACA device detection\n");
+
+       return retval;
+}
+
 static int penwell_otg_probe(struct pci_dev *pdev,
                const struct pci_device_id *id)
 {
@@ -2819,6 +3331,8 @@ static int penwell_otg_probe(struct pci_dev *pdev,
        pnw->iotg.start_hnp_poll = penwell_otg_start_hnp_poll;
        pnw->iotg.stop_hnp_poll = penwell_otg_stop_hnp_poll;
        pnw->iotg.otg.state = OTG_STATE_UNDEFINED;
+       pnw->rt_resuming = 0;
+       pnw->queue_stop = 0;
        if (otg_set_transceiver(&pnw->iotg.otg)) {
                dev_dbg(pnw->dev, "can't set transceiver\n");
                retval = -EBUSY;
@@ -2829,6 +3343,7 @@ static int penwell_otg_probe(struct pci_dev *pdev,
        pnw->iotg.ulpi_ops.write = penwell_otg_ulpi_write;
 
        spin_lock_init(&pnw->iotg.hnp_poll_lock);
+       spin_lock_init(&pnw->notify_lock);
 
        init_timer(&pnw->hsm_timer);
        init_timer(&pnw->bus_mon_timer);
@@ -2854,8 +3369,24 @@ static int penwell_otg_probe(struct pci_dev *pdev,
        pnw->msic = penwell_otg_check_msic();
 
        penwell_otg_phy_low_power(0);
+       /* Workaround for ULPI lockup issue, need turn off PHY 4ms */
+       penwell_otg_phy_enable(0);
+       usleep_range(4000, 4500);
        penwell_otg_phy_enable(1);
 
+       /* Enable ID pullup immediately after reeable PHY */
+       val32 = readl(pnw->iotg.base + CI_OTGSC);
+       writel(val32 | OTGSC_IDPU, pnw->iotg.base + CI_OTGSC);
+
+       /* Wait correct value to be synced */
+       set_host_mode();
+       usleep_range(2000, 3000);
+       penwell_otg_phy_low_power(1);
+       msleep(100);
+
+       /* enable ACA device detection */
+       penwell_otg_aca_enable();
+
        reset_otg();
        init_hsm();
 
@@ -2900,12 +3431,11 @@ static int penwell_otg_probe(struct pci_dev *pdev,
                goto err;
        }
 
-       if (pnw->iotg.otg.state == OTG_STATE_A_IDLE)
-               queue_work(pnw->qwork, &pnw->work);
-
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
 
+       penwell_update_transceiver();
+
        return 0;
 
 err:
@@ -2950,40 +3480,61 @@ static void penwell_otg_remove(struct pci_dev *pdev)
        pnw = NULL;
 }
 
-static void transceiver_suspend(struct pci_dev *pdev)
+void penwell_otg_shutdown(struct pci_dev *pdev)
 {
-       penwell_otg_phy_low_power(1);
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
+       struct penwell_otg *pnw = the_transceiver;
+
+       dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+       /* Disable MSIC Interrupt Notifications */
+       penwell_otg_msic_spi_access(true);
+
+       penwell_otg_msic_write(MSIC_INT_EN_RISE_CLR, 0x1F);
+       penwell_otg_msic_write(MSIC_INT_EN_FALL_CLR, 0x1F);
+
+       penwell_otg_msic_spi_access(false);
+
+       dev_dbg(pnw->dev, "%s <---\n", __func__);
 }
 
-static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
+static int penwell_otg_suspend(struct device *dev)
 {
        struct penwell_otg              *pnw = the_transceiver;
        struct intel_mid_otg_xceiv      *iotg = &pnw->iotg;
+       struct pci_dev                  *pdev;
+       unsigned long                   flags;
        int                             ret = 0;
 
+       pdev = to_pci_dev(dev);
+
+       dev_dbg(pnw->dev, "%s --->\n", __func__);
+
+       if (iotg->otg.state == OTG_STATE_B_PERIPHERAL) {
+               dev_dbg(pnw->dev, "still alive, don't suspend\n");
+               return -EBUSY;
+       }
+
        /* Disbale OTG interrupts */
        penwell_otg_intr(0);
 
-       if (pdev->irq)
-               free_irq(pdev->irq, pnw);
+       /* Stop queue work from notifier */
+       spin_lock_irqsave(&pnw->notify_lock, flags);
+       pnw->queue_stop = 1;
+       spin_unlock_irqrestore(&pnw->notify_lock, flags);
 
-       /* Prevent more otg_work */
        flush_workqueue(pnw->qwork);
-       destroy_workqueue(pnw->qwork);
-       pnw->qwork = NULL;
 
        /* start actions */
        switch (iotg->otg.state) {
+       case OTG_STATE_A_VBUS_ERR:
+               set_host_mode();
+               iotg->otg.state = OTG_STATE_A_IDLE;
+               break;
        case OTG_STATE_A_WAIT_VFALL:
+               penwell_otg_del_timer(TA_WAIT_VFALL_TMR);
                iotg->otg.state = OTG_STATE_A_IDLE;
        case OTG_STATE_A_IDLE:
-       case OTG_STATE_A_VBUS_ERR:
-               transceiver_suspend(pdev);
-               break;
        case OTG_STATE_B_IDLE:
-               transceiver_suspend(pdev);
                break;
        case OTG_STATE_A_WAIT_VRISE:
                penwell_otg_del_timer(TA_WAIT_VRISE_TMR);
@@ -2992,7 +3543,6 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
                /* Turn off VBus */
                iotg->otg.set_vbus(&iotg->otg, false);
                iotg->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
                break;
        case OTG_STATE_A_WAIT_BCON:
                penwell_otg_del_timer(TA_WAIT_BCON_TMR);
@@ -3003,27 +3553,15 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
 
                iotg->hsm.a_srp_det = 0;
 
+               penwell_otg_phy_vbus_wakeup(false);
+
                /* Turn off VBus */
                iotg->otg.set_vbus(&iotg->otg, false);
                iotg->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
                break;
        case OTG_STATE_A_HOST:
-               /* Stop HNP polling */
-               iotg->stop_hnp_poll(iotg);
-
-               if (pnw->iotg.stop_host)
-                       pnw->iotg.stop_host(&pnw->iotg);
-               else
-                       dev_dbg(pnw->dev, "host driver has been stopped.\n");
-
-               iotg->hsm.a_srp_det = 0;
-
-               /* Turn off VBus */
-               iotg->otg.set_vbus(&iotg->otg, false);
-
-               iotg->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
+               dev_dbg(pnw->dev, "don't suspend, host still alive\n");
+               ret = -EBUSY;
                break;
        case OTG_STATE_A_SUSPEND:
                penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
@@ -3034,10 +3572,11 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
                        dev_dbg(pnw->dev, "host driver has been removed.\n");
                iotg->hsm.a_srp_det = 0;
 
+               penwell_otg_phy_vbus_wakeup(false);
+
                /* Turn off VBus */
                iotg->otg.set_vbus(&iotg->otg, false);
                iotg->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
                break;
        case OTG_STATE_A_PERIPHERAL:
                penwell_otg_del_timer(TA_BIDL_ADIS_TMR);
@@ -3051,7 +3590,6 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
                iotg->otg.set_vbus(&iotg->otg, false);
                iotg->hsm.a_srp_det = 0;
                iotg->otg.state = OTG_STATE_A_IDLE;
-               transceiver_suspend(pdev);
                break;
        case OTG_STATE_B_HOST:
                /* Stop HNP polling */
@@ -3063,15 +3601,10 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
                        dev_dbg(pnw->dev, "host driver has been stopped.\n");
                iotg->hsm.b_bus_req = 0;
                iotg->otg.state = OTG_STATE_B_IDLE;
-               transceiver_suspend(pdev);
                break;
        case OTG_STATE_B_PERIPHERAL:
-               if (pnw->iotg.stop_peripheral)
-                       pnw->iotg.stop_peripheral(&pnw->iotg);
-               else
-                       dev_dbg(pnw->dev, "client driver has been stopped.\n");
-               iotg->otg.state = OTG_STATE_B_IDLE;
-               transceiver_suspend(pdev);
+               dev_dbg(pnw->dev, "don't suspend, client still alive\n");
+               ret = -EBUSY;
                break;
        case OTG_STATE_B_WAIT_ACON:
                penwell_otg_del_timer(TB_ASE0_BRST_TMR);
@@ -3084,50 +3617,63 @@ static int penwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
                        dev_dbg(pnw->dev, "host driver has been stopped.\n");
                iotg->hsm.b_bus_req = 0;
                iotg->otg.state = OTG_STATE_B_IDLE;
-               transceiver_suspend(pdev);
                break;
        default:
                dev_dbg(pnw->dev, "error state before suspend\n");
                break;
        }
 
-       return ret;
-}
+       if (ret) {
+               /* allow queue work from notifier */
+               spin_lock_irqsave(&pnw->notify_lock, flags);
+               pnw->queue_stop = 0;
+               spin_unlock_irqrestore(&pnw->notify_lock, flags);
 
-static void transceiver_resume(struct pci_dev *pdev)
-{
-       pci_restore_state(pdev);
-       pci_set_power_state(pdev, PCI_D0);
+               penwell_otg_intr(1);
+
+               penwell_update_transceiver();
+       } else {
+               penwell_otg_phy_low_power(1);
+               penwell_otg_vusb330_low_power(1);
+       }
+
+       dev_dbg(pnw->dev, "%s <---\n", __func__);
+       return ret;
 }
 
-static int penwell_otg_resume(struct pci_dev *pdev)
+static int penwell_otg_resume(struct device *dev)
 {
        struct penwell_otg      *pnw = the_transceiver;
+       struct pci_dev          *pdev;
        int                     ret = 0;
+       unsigned long           flags;
 
-       transceiver_resume(pdev);
+       pdev = to_pci_dev(dev);
 
-       pnw->qwork = create_singlethread_workqueue("penwell_otg_queue");
-       if (!pnw->qwork) {
-               dev_dbg(pnw->dev, "cannot create penwell otg workqueue\n");
-               ret = -ENOMEM;
-               goto error;
-       }
+       dev_dbg(pnw->dev, "%s --->\n", __func__);
 
-       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
-                               driver_name, pnw) != 0) {
-               dev_dbg(pnw->dev, "request irq %d failed\n", pdev->irq);
-               ret = -EBUSY;
-               goto error;
-       }
+       penwell_otg_vusb330_low_power(0);
+
+       /* D3->D0 controller will be reset, so reset work mode and PHY state
+        * which is cleared by the reset */
 
        switch (pnw->iotg.otg.state) {
        case OTG_STATE_B_IDLE:
                break;
+       case OTG_STATE_A_IDLE:
+               penwell_otg_phy_vbus_wakeup(true);
+               /* Provide power as default */
+               pnw->iotg.hsm.a_bus_req = 1;
+               break;
        default:
                break;
        }
 
+       /* allow queue work from notifier */
+       spin_lock_irqsave(&pnw->notify_lock, flags);
+       pnw->queue_stop = 0;
+       spin_unlock_irqrestore(&pnw->notify_lock, flags);
+
        /* enable OTG interrupts */
        penwell_otg_intr(1);
 
@@ -3135,10 +3681,7 @@ static int penwell_otg_resume(struct pci_dev *pdev)
 
        penwell_update_transceiver();
 
-       return ret;
-error:
-       penwell_otg_intr(0);
-       transceiver_suspend(pdev);
+       dev_dbg(pnw->dev, "%s <---\n", __func__);
        return ret;
 }
 
@@ -3149,6 +3692,7 @@ static int penwell_otg_runtime_suspend(struct device *dev)
        struct penwell_otg      *pnw = the_transceiver;
        struct pci_dev          *pdev;
        int                     ret = 0;
+       u32                     val;
 
        dev_dbg(dev, "%s --->\n", __func__);
 
@@ -3156,12 +3700,14 @@ static int penwell_otg_runtime_suspend(struct device *dev)
 
        switch (pnw->iotg.otg.state) {
        case OTG_STATE_A_IDLE:
+               break;
        case OTG_STATE_B_IDLE:
-               /* Transceiver handle it itself */
-               penwell_otg_phy_low_power(1);
-               pci_save_state(pdev);
-               pci_disable_device(pdev);
-               pci_set_power_state(pdev, PCI_D3hot);
+               val = readl(pnw->iotg.base + CI_USBMODE);
+               if (!(val & USBMODE_CM)) {
+                       /* Controller needs to reset & set mode */
+                       dev_dbg(dev, "reset to client mode\n");
+                       set_client_mode();
+               }
                break;
        case OTG_STATE_A_WAIT_BCON:
        case OTG_STATE_A_HOST:
@@ -3178,6 +3724,12 @@ static int penwell_otg_runtime_suspend(struct device *dev)
                break;
        }
 
+       penwell_otg_phy_low_power(1);
+
+       msleep(2);
+
+       penwell_otg_vusb330_low_power(1);
+
        dev_dbg(dev, "%s <---\n", __func__);
        return ret;
 }
@@ -3187,30 +3739,38 @@ static int penwell_otg_runtime_resume(struct device *dev)
        struct penwell_otg      *pnw = the_transceiver;
        struct pci_dev          *pdev;
        int                     ret = 0;
+       u32                     val;
 
        dev_dbg(dev, "%s --->\n", __func__);
 
        pdev = to_pci_dev(dev);
 
+       if (pnw->rt_resuming) {
+               dev_dbg(pnw->dev, "%s  rt_resuming--->\n", __func__);
+               penwell_otg_check_wakeup_event(pnw);
+       }
+
+       penwell_otg_vusb330_low_power(0);
        penwell_otg_intr(1);
-       penwell_otg_phy_low_power(0);
 
        switch (pnw->iotg.otg.state) {
        case OTG_STATE_A_IDLE:
+               break;
        case OTG_STATE_B_IDLE:
-               /* Transceiver handle it itself */
-               pci_set_power_state(pdev, PCI_D0);
-               pci_restore_state(pdev);
-               ret = pci_enable_device(pdev);
-               if (ret)
-                       dev_err(&pdev->dev, "device cant be enabled\n");
-               penwell_otg_phy_low_power(0);
+               val = readl(pnw->iotg.base + CI_USBMODE);
+               if (!(val & USBMODE_CM)) {
+                       /* Controller needs to reset & set mode */
+                       dev_dbg(dev, "reset to client mode\n");
+                       set_client_mode();
+               }
                break;
        case OTG_STATE_A_WAIT_BCON:
        case OTG_STATE_A_HOST:
        case OTG_STATE_A_SUSPEND:
-               if (pnw->iotg.runtime_resume_host)
+               if (pnw->iotg.runtime_resume_host) {
+                       penwell_otg_phy_low_power(0);
                        ret = pnw->iotg.runtime_resume_host(&pnw->iotg);
+               }
                break;
        case OTG_STATE_A_PERIPHERAL:
        case OTG_STATE_B_PERIPHERAL:
@@ -3221,6 +3781,13 @@ static int penwell_otg_runtime_resume(struct device *dev)
                break;
        }
 
+       if (pnw->rt_resuming) {
+               dev_dbg(pnw->dev, "irq num: %d\n", pnw->rt_resuming);
+               pnw->rt_resuming = 0;
+
+               pm_runtime_put(pnw->dev);
+       }
+
        dev_dbg(dev, "%s <---\n", __func__);
        return 0;
 }
@@ -3243,9 +3810,12 @@ static int penwell_otg_runtime_idle(struct device *dev)
                break;
        }
 
+       /* some delay for stability */
+       pm_schedule_suspend(dev, 500);
+
        dev_dbg(dev, "%s <---\n", __func__);
 
-       return 0;
+       return -EBUSY;
 }
 
 #else
@@ -3272,6 +3842,8 @@ static const struct dev_pm_ops penwell_otg_pm_ops = {
        .runtime_suspend = penwell_otg_runtime_suspend,
        .runtime_resume = penwell_otg_runtime_resume,
        .runtime_idle = penwell_otg_runtime_idle,
+       .suspend = penwell_otg_suspend,
+       .resume = penwell_otg_resume,
 };
 
 static struct pci_driver otg_pci_driver = {
@@ -3280,10 +3852,7 @@ static struct pci_driver otg_pci_driver = {
 
        .probe =        penwell_otg_probe,
        .remove =       penwell_otg_remove,
-
-       .suspend =      penwell_otg_suspend,
-       .resume =       penwell_otg_resume,
-
+       .shutdown =     penwell_otg_shutdown,
        .driver = {
                .pm =   &penwell_otg_pm_ops
        },
index 6ec27fb..c00fb37 100644 (file)
 #define        TEST_FORCE_EN   5
 
 /*
+ * USB OTG 2.0 Test Mode
+ * See OTG 2.0 spec Table 6-8
+ */
+#define        TEST_SRP_REQD   6
+#define        TEST_HNP_REQD   7
+
+/*
  * OTG 2.0
  * Section 6.2 & 6.3
  */
index 0b818ab..a3205b7 100644 (file)
@@ -703,6 +703,11 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
        return gadget->ops->pullup(gadget, 0);
 }
 
+enum gadget_driver_state {
+       REGISTERED,
+       UNREGISTERED,
+       BIND_UNBIND,
+};
 
 /*-------------------------------------------------------------------------*/
 
@@ -774,6 +779,8 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
 struct usb_gadget_driver {
        char                    *function;
        enum usb_device_speed   speed;
+       enum gadget_driver_state drv_state;
+       unsigned                ep_max;
        void                    (*unbind)(struct usb_gadget *);
        int                     (*setup)(struct usb_gadget *,
                                        const struct usb_ctrlrequest *);
index ca2c4a6..013e6ee 100644 (file)
@@ -73,6 +73,8 @@ struct otg_hsm {
        int b_srp_fail_tmout;
        int b_srp_fail_tmr;
        int b_adp_sense_tmout;
+       int tst_maint_tmout;
+       int tst_noadp_tmout;
 
        /* Informative variables */
        int a_bus_drop;
@@ -89,6 +91,11 @@ struct otg_hsm {
 
        /* Others */
        int vbus_srp_up;
+
+       /* Test Mode */
+       int otg_srp_reqd;
+       int otg_hnp_reqd;
+       int otg_vbus_off;
 };
 
 /* must provide ULPI access function to read/write registers implemented in
@@ -178,6 +185,11 @@ struct intel_mid_otg_xceiv *otg_to_mid_xceiv(struct otg_transceiver *otg)
 #define MID_OTG_NOTIFY_CLIENTREMOVE    0x000a
 #define MID_OTG_NOTIFY_CLIENTFS                0x000b
 #define MID_OTG_NOTIFY_CLIENTHS                0x000c
+#define        MID_OTG_NOTIFY_CRESET           0x000d
+
+#define        MID_OTG_NOTIFY_TEST_SRP_REQD    0x0101
+#define        MID_OTG_NOTIFY_TEST_VBUS_OFF    0x0102
+#define        MID_OTG_NOTIFY_TEST             0x0103
 
 static inline int
 intel_mid_otg_register_notifier(struct intel_mid_otg_xceiv *iotg,
index ab959cb..7372415 100644 (file)
@@ -178,6 +178,7 @@ struct langwell_op_regs {
 #define        PORTS_WKDS      BIT(21) /* wake on disconnect enable */
 #define        PORTS_WKCN      BIT(20) /* wake on connect enable */
 #define        PORTS_PTC(p)    (((p)>>16)&0xf) /* bits 19:16, port test control */
+#define        PORTS_PTC_MASK  (BIT(16) | BIT(17) | BIT(18) | BIT(19))
 #define        PORTS_PIC       (BIT(15) | BIT(14))     /* port indicator control */
 #define        PORTS_PO        BIT(13) /* port owner */
 #define        PORTS_PP        BIT(12) /* port power */
@@ -207,6 +208,7 @@ struct langwell_op_regs {
 #define        LPM_SRT         BIT(24) /* shorten reset time */
 #define        LPM_PFSC        BIT(23) /* port force full speed connect */
 #define        LPM_PHCD        BIT(22) /* PHY low power suspend clock disable */
+#define        LPM_ASUS        BIT(17) /* auto Low Power */
 #define        LPM_STL         BIT(16) /* STALL reply to LPM token */
 #define        LPM_BA(d)       \
        (((d)>>1)&0x7ff)        /* bits 11:1, BmAttributes */
index e77db06..8035d91 100644 (file)
 #define MSIC_OTGCTRL           0x39c
 #define MSIC_OTGCTRLSET                0x340
 #define MSIC_OTGCTRLCLR                0x341
+#define        ULPI_OTGCTRL            0x0a
+#define        ULPI_OTGCTRLSET         0x0b
+#define        ULPI_OTGCTRLCLR         0x0c
 #      define DMPULLDOWN               BIT(2)
 #      define DPPULLDOWN               BIT(1)
+#define MSIC_USBINTEN_RISE     0x39d
+#define MSIC_USBINTEN_RISESET  0x39e
+#define MSIC_USBINTEN_RISECLR  0x39f
+#define MSIC_USBINTEN_FALL     0x3a0
+#define MSIC_USBINTEN_FALLSET  0x3a1
+#define MSIC_USBINTEN_FALLCLR  0x3a2
+#      define IDGND                    BIT(4)
+#      define SESSEND                  BIT(3)
+#      define SESSVLD                  BIT(2)
+#      define VBUSVLD                  BIT(1)
+#      define HOSTDISCON               BIT(0)
 #define MSIC_PWRCTRL           0x3b5
 #define MSIC_PWRCTRLSET                0x342
 #define MSIC_PWRCTRLCLR                0x343
+#define ULPI_PWRCTRL           0x3d
+#define ULPI_PWRCTRLSET                0x3e
+#define ULPI_PWRCTRLCLR                0x3f
 #      define HWDET                    BIT(7)
 #      define DPVSRCEN                 BIT(6)
+#      define VDATDET                  BIT(5)
 #      define DPWKPUEN                 BIT(4)
 #      define SWCNTRL                  BIT(0)
 #define MSIC_FUNCTRL           0x398
 #define MSIC_FUNCTRLSET                0x344
 #define MSIC_FUNCTRLCLR                0x345
+#define ULPI_FUNCTRL           0x04
+#define ULPI_FUNCTRLSET                0x05
+#define ULPI_FUNCTRLCLR                0x06
 #      define OPMODE1                  BIT(4)
 #      define OPMODE0                  BIT(3)
+#      define TERMSELECT               BIT(2)
+#      define XCVRSELECT1              BIT(1)
+#      define XCVRSELECT0              BIT(0)
+#define MSIC_VS1               0x3b6
+#define MSIC_VS1SET            0x3a9
+#define MSIC_VS1CLR            0x3aa
+#define ULPI_VS1               0x80
+#define ULPI_VS1SET            0x81
+#define ULPI_VS1CLR            0x82
+#      define DATAPOLARITY             BIT(6)
 #define MSIC_VS3               0x3b9
 #define MSIC_VS3SET            0x346   /* Vendor Specific */
 #define MSIC_VS3CLR            0x347
 #      define SWUSBDET                 BIT(4)
 #      define DATACONEN                BIT(3)
+#define ULPI_VS3               0x85
+#define ULPI_VS3SET            0x86
+#define ULPI_VS3CLR            0x87
+#      define CHGD_IDP_SRC             BIT(6)
+#      define IDPULLUP_WK              BIT(5)
+#      define SWUSBDET                 BIT(4)
+#      define DATACONEN                BIT(3)
+#define MSIC_VS4               0x3ba
+#define MSIC_VS4SET            0x3ab
+#define MSIC_VS4CLR            0x3ac
+#define ULPI_VS4               0x88
+#define ULPI_VS4SET            0x89
+#define ULPI_VS4CLR            0x8a
+#      define ACADET                   BIT(6)
+#      define RABUSIN                  BIT(5)
+#      define R1KERIES                 BIT(4)
+#      define CHRG_SERX_DP             BIT(1)
+#      define CHRG_SERX_DM             BIT(0)
 #define MSIC_ULPIACCESSMODE    0x348
 #      define SPIMODE                  BIT(0)
+#define MSIC_INT_EN_RISE       0x39D
+#define MSIC_INT_EN_RISE_SET   0x39E
+#define MSIC_INT_EN_RISE_CLR   0x39F
+#define MSIC_INT_EN_FALL       0x3A0
+#define MSIC_INT_EN_FALL_SET   0x3A1
+#define MSIC_INT_EN_FALL_CLR   0x3A2
 
 /* MSIC TI implementation for ADP/ACA */
+#define SPI_TI_VS2             0x3B7
+#define SPI_TI_VS2_LATCH       0x3B8
+#define SPI_TI_VS4             0x3BA
+#define SPI_TI_VS5             0x3BB
+#define ULPI_TI_USB_INT_STS    0x13
+#define ULPI_TI_USB_INT_LAT    0x14
+#      define USB_INT_IDGND            BIT(4)
+#      define USB_INT_SESSEND          BIT(3)
+#      define USB_INT_SESSVLD          BIT(2)
+#      define USB_INT_VBUSVLD          BIT(1)
 #define ULPI_TI_VS2            0x83
 #      define TI_ID_FLOAT_STS          BIT(4)
 #      define TI_ID_RARBRC_STS(d)      (((d)>>2)&3)
@@ -227,7 +292,9 @@ enum penwell_otg_timer_type {
        TB_ASE0_BRST_TMR,
        TB_SE0_SRP_TMR,
        TB_SRP_FAIL_TMR, /* wait for response of SRP */
-       TB_BUS_SUSPEND_TMR
+       TB_BUS_SUSPEND_TMR,
+       TTST_MAINT_TMR,
+       TTST_NOADP_TMR,
 };
 
 #define TA_WAIT_VRISE          100
@@ -242,6 +309,9 @@ enum penwell_otg_timer_type {
 #define TB_SRP_FAIL            5500
 #define TB_BUS_SUSPEND         500
 #define THOS_REQ_POL           1500
+/* Test mode */
+#define        TTST_MAINT              9900
+#define        TTST_NOADP              5000
 
 /* MSIC vendor information */
 enum msic_vendor {
@@ -314,6 +384,8 @@ struct penwell_otg {
        enum msic_vendor                msic;
 
        struct notifier_block           iotg_notifier;
+       spinlock_t                      notify_lock;
+       int                             queue_stop;
 
        struct adp_status               adp;
 
@@ -321,6 +393,8 @@ struct penwell_otg {
        struct otg_bc_cap               charging_cap;
        int (*bc_callback)(void *arg, int event, struct otg_bc_cap *cap);
        void                            *bc_arg;
+
+       unsigned                        rt_resuming;
 };
 
 static inline