Merge "usb: msm_otg: Allow support to use 2nd HSPHY with USB2 Core"
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index efd33e7..6d06e99 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -69,6 +69,8 @@
 - qcom,dp-manual-pullup: If present, vbus is not routed to USB controller/phy
 	and controller driver therefore enables pull-up explicitly before
 	starting controller using usbcmd run/stop bit.
+- qcom,usb2-enable-hsphy2: If present then USB2 controller is connected to 2nd
+	HSPHY.
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 569f200..3cad3ce 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -98,6 +98,32 @@
 	}
 }
 
+static void ci13xxx_msm_reset(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+	struct device *dev = udc->gadget.dev.parent;
+
+	writel_relaxed(0, USB_AHBBURST);
+	writel_relaxed(0x08, USB_AHBMODE);
+
+	if (phy && (phy->flags & ENABLE_SECONDARY_PHY)) {
+		int	temp;
+
+		dev_dbg(dev, "using secondary hsphy\n");
+		temp = readl_relaxed(USB_PHY_CTRL2);
+		temp |= (1<<16);
+		writel_relaxed(temp, USB_PHY_CTRL2);
+
+		/*
+		 * Add memory barrier to make sure above LINK writes are
+		 * complete before moving ahead with USB peripheral mode
+		 * enumeration.
+		 */
+		mb();
+	}
+}
+
 static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
 {
 	struct device *dev = udc->gadget.dev.parent;
@@ -105,8 +131,7 @@
 	switch (event) {
 	case CI13XXX_CONTROLLER_RESET_EVENT:
 		dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
-		writel(0, USB_AHBBURST);
-		writel_relaxed(0x08, USB_AHBMODE);
+		ci13xxx_msm_reset();
 		break;
 	case CI13XXX_CONTROLLER_DISCONNECT_EVENT:
 		dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index bc6580b..4865b03 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -478,6 +478,7 @@
 	u32 val;
 	int ret;
 	int retries;
+	struct msm_otg_platform_data *pdata = motg->pdata;
 
 	ret = msm_otg_link_clk_reset(motg, 1);
 	if (ret)
@@ -496,6 +497,9 @@
 	if (ret)
 		return ret;
 
+	if (pdata && pdata->enable_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+							USB_PHY_CTRL2);
 	val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK;
 	writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
 
@@ -535,6 +539,7 @@
 static int msm_otg_link_reset(struct msm_otg *motg)
 {
 	int cnt = 0;
+	struct msm_otg_platform_data *pdata = motg->pdata;
 
 	writel_relaxed(USBCMD_RESET, USB_USBCMD);
 	while (cnt < LINK_RESET_TIMEOUT_USEC) {
@@ -551,6 +556,9 @@
 	writel_relaxed(0x0, USB_AHBBURST);
 	writel_relaxed(0x08, USB_AHBMODE);
 
+	if (pdata && pdata->enable_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+								USB_PHY_CTRL2);
 	return 0;
 }
 
@@ -3796,6 +3804,8 @@
 				"qcom,hsusb-otg-delay-lpm");
 	pdata->dp_manual_pullup = of_property_read_bool(node,
 				"qcom,dp-manual-pullup");
+	pdata->enable_sec_phy = of_property_read_bool(node,
+					"qcom,usb2-enable-hsphy2");
 
 	pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
 	if (pdata->pmic_id_irq < 0)
@@ -4095,6 +4105,9 @@
 	if (pdata->dp_manual_pullup)
 		phy->flags |= ENABLE_DP_MANUAL_PULLUP;
 
+	if (pdata->enable_sec_phy)
+		phy->flags |= ENABLE_SECONDARY_PHY;
+
 	ret = usb_set_transceiver(&motg->phy);
 	if (ret) {
 		dev_err(&pdev->dev, "usb_set_transceiver failed\n");
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index c8a20da..5e73bd9 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -201,6 +201,7 @@
  *              USB enters LPM.
  * @delay_lpm_on_disconnect: Use a delay before entering LPM
  *              upon USB cable disconnection.
+ * @enable_sec_phy: Use second HSPHY with USB2 core
  * @bus_scale_table: parameters for bus bandwidth requirements
  * @mhl_dev_name: MHL device name used to register with MHL driver.
  */
@@ -222,12 +223,14 @@
 	bool core_clk_always_on_workaround;
 	bool delay_lpm_on_disconnect;
 	bool dp_manual_pullup;
+	bool enable_sec_phy;
 	struct msm_bus_scale_pdata *bus_scale_table;
 	const char *mhl_dev_name;
 };
 
 /* phy related flags */
 #define ENABLE_DP_MANUAL_PULLUP		BIT(0)
+#define ENABLE_SECONDARY_PHY		BIT(1)
 
 /* Timeout (in msec) values (min - max) associated with OTG timers */