diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 4878d18..aa78c1b 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -334,6 +334,8 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
 				usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
 		}
 
+		usb_status |= dwc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+
 		break;
 
 	case USB_RECIP_INTERFACE:
@@ -448,11 +450,45 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
 
 	switch (wValue) {
 	case USB_DEVICE_REMOTE_WAKEUP:
+		if (set)
+			dwc->remote_wakeup = 1;
+		else
+			dwc->remote_wakeup = 0;
 		break;
-	/*
-	 * 9.4.1 says only only for SS, in AddressState only for
-	 * default control pipe
-	 */
+	case USB_DEVICE_B_HNP_ENABLE:
+		dev_dbg(dwc->dev,
+			"SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+		if (set && dwc->gadget.is_otg) {
+			if (dwc->gadget.host_request_flag) {
+				struct usb_phy *phy =
+					usb_get_phy(USB_PHY_TYPE_USB3);
+
+				dwc->gadget.b_hnp_enable = 0;
+				dwc->gadget.host_request_flag = 0;
+				otg_start_hnp(phy->otg);
+				usb_put_phy(phy);
+			} else {
+				dwc->gadget.b_hnp_enable = 1;
+			}
+		} else
+			return -EINVAL;
+		break;
+
+	case USB_DEVICE_A_HNP_SUPPORT:
+		/* RH port supports HNP */
+		dev_dbg(dwc->dev,
+			"SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
+		break;
+
+	case USB_DEVICE_A_ALT_HNP_SUPPORT:
+		/* other RH port does */
+		dev_dbg(dwc->dev,
+			"SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+		break;
+		/*
+		 * 9.4.1 says only only for SS, in AddressState only for
+		 * default control pipe
+		 */
 	case USB_DEVICE_U1_ENABLE:
 		ret = dwc3_ep0_handle_u1(dwc, state, set);
 		break;
@@ -759,7 +795,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 
 	switch (ctrl->bRequest) {
 	case USB_REQ_GET_STATUS:
-		ret = dwc3_ep0_handle_status(dwc, ctrl);
+		if (le16_to_cpu(ctrl->wIndex) == OTG_STS_SELECTOR)
+			ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		else
+			ret = dwc3_ep0_handle_status(dwc, ctrl);
 		break;
 	case USB_REQ_CLEAR_FEATURE:
 		ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 6785595..3b0b771 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -34,6 +34,7 @@
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
+#include "otg.h"
 
 /**
  * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
@@ -1792,25 +1793,51 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 	int			ret = 0;
 	int			irq;
 
-	irq = dwc->irq_gadget;
-	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
-			IRQF_SHARED, "dwc3", dwc->ev_buf);
-	if (ret) {
-		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
-				irq, ret);
-		goto err0;
-	}
-
 	spin_lock_irqsave(&dwc->lock, flags);
 	if (dwc->gadget_driver) {
 		dev_err(dwc->dev, "%s is already bound to %s\n",
 				dwc->gadget.name,
 				dwc->gadget_driver->driver.name);
 		ret = -EBUSY;
-		goto err1;
+		goto err0;
 	}
 
-	dwc->gadget_driver	= driver;
+	if (g->is_otg) {
+		static struct usb_gadget_driver *prev_driver;
+		/* There are two instances where OTG functionality is enabled :
+		 * 1. This function will be called from OTG driver to start the
+		 * gadget
+		 * 2. This function will be called by the Linux Class Driver to
+		 * start the gadget
+		 * Below code will keep synchronization between these calls. The
+		 * "driver" argument will be NULL when it is called from the OTG
+		 * driver, so we are maintaning a global variable "prev_driver"
+		 * to assign value of argument "driver" (from class driver) to
+		 * dwc->gadget_driver when it is called from OTG.
+		 */
+		if (driver) {
+			prev_driver	= driver;
+			if (dwc->otg) {
+				struct dwc3_otg		*otg = dwc->otg;
+
+				if ((otg->host_started ||
+						(!otg->peripheral_started)))
+					goto err0;
+			}
+			dwc->gadget_driver	= driver;
+		} else
+			dwc->gadget_driver	= prev_driver;
+	} else
+		dwc->gadget_driver	= driver;
+
+	irq = dwc->irq_gadget;
+	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+			IRQF_SHARED, "dwc3", dwc->ev_buf);
+	if (ret) {
+		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				irq, ret);
+		goto err0;
+	}
 
 	if (pm_runtime_active(dwc->dev))
 		__dwc3_gadget_start(dwc);
@@ -1819,11 +1846,9 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 
 	return 0;
 
-err1:
-	spin_unlock_irqrestore(&dwc->lock, flags);
-	free_irq(irq, dwc);
-
 err0:
+	dwc->gadget_driver = NULL;
+	spin_unlock_irqrestore(&dwc->lock, flags);
 	return ret;
 }
 
@@ -2977,6 +3002,18 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 
 	dwc->irq_gadget = irq;
 
+	if (dwc->dr_mode == USB_DR_MODE_OTG) {
+		struct usb_phy *phy;
+		/* Switch otg to peripheral mode */
+		phy = usb_get_phy(USB_PHY_TYPE_USB3);
+		if (!IS_ERR(phy)) {
+			if (phy && phy->otg)
+				otg_set_peripheral(phy->otg,
+						(struct usb_gadget *)(long)1);
+			usb_put_phy(phy);
+		}
+	}
+
 	dwc->ctrl_req = dma_alloc_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
 			&dwc->ctrl_req_addr, GFP_KERNEL);
 	if (!dwc->ctrl_req) {
@@ -3066,6 +3103,26 @@ int dwc3_gadget_init(struct dwc3 *dwc)
 		goto err5;
 	}
 
+	if (dwc->dr_mode == USB_DR_MODE_OTG) {
+		struct usb_phy *phy;
+
+		phy = usb_get_phy(USB_PHY_TYPE_USB3);
+		if (!IS_ERR(phy)) {
+			if (phy && phy->otg) {
+				ret = otg_set_peripheral(phy->otg,
+						&dwc->gadget);
+				if (ret) {
+					usb_put_phy(phy);
+					phy = NULL;
+					goto err5;
+				}
+			} else {
+				usb_put_phy(phy);
+				phy = NULL;
+			}
+		}
+	}
+
 	return 0;
 
 err5:
