ehci: hsic: Add resume gpio support

some peripherals connected to hsic controller cannot wakeup from XO
shutdown using in-band bus resume signalling. If present, use resume
gpio to bring peripherals out of XO shutdown before resuming the bus.

Change-Id: I7b80c95f31e854a09e673a9367ab85e4977a0fa0
Signed-off-by: Vamsi Krishna <vskrishn@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 1885e8a..9f8bbd9 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -15,7 +15,10 @@
 	"wakeup" : Wakeup interrupt from HSIC during suspend (or XO shutdown).
 - hsic,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
   in Documentation/devicetree/bindings/gpio/gpio.txt.
-  Optional "gpio-name" can be "strobe" and "data".
+  Optional "gpio-name" can be "strobe", "data" and "resume".
+- hsic,resume-gpio : if present then periperal connected to hsic controller
+  cannot wakeup from XO shutdown using in-band hsic resume. Use resume
+  gpio to wakeup peripheral
 - hsic,ignore-cal-pad-config : If present then HSIC CAL PAD configuration
   using TLMM is not performed.
 - hsic,strobe-pad-offset : Offset of TLMM register for configuring HSIC
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 8c0894c..ca4b01a 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -624,6 +624,15 @@
 	int ret;
 	void __iomem *reg;
 
+	if (pdata && pdata->resume_gpio) {
+		ret = gpio_request(pdata->resume_gpio, "HSIC_RESUME_GPIO");
+		if (ret < 0) {
+			dev_err(mehci->dev,
+				"gpio req failed for hsic resume:%d\n", ret);
+			pdata->resume_gpio = 0;
+		}
+	}
+
 	/* HSIC init sequence when HSIC signals (Strobe/Data) are
 	routed via GPIOs */
 	if (pdata && pdata->strobe && pdata->data) {
@@ -645,7 +654,7 @@
 		ret = msm_hsic_config_gpios(mehci, 1);
 		if (ret) {
 			dev_err(mehci->dev, " gpio configuarion failed\n");
-			return ret;
+			goto free_resume_gpio;
 		}
 		if (pdata->strobe_pad_offset) {
 			/* Set CORE_CTL_EN in STROBE GPIO PAD_CTL register */
@@ -694,6 +703,12 @@
 	ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL));
 
 	return 0;
+
+free_resume_gpio:
+	if (pdata && pdata->resume_gpio)
+		gpio_free(pdata->resume_gpio);
+
+	return ret;
 }
 
 #define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
@@ -1312,6 +1327,10 @@
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	u32			temp;
 	struct task_struct	*resume_thread = NULL;
+	struct msm_hsic_host_platform_data *pdata =  mehci->dev->platform_data;
+
+	if (pdata->resume_gpio)
+		gpio_direction_output(pdata->resume_gpio, 1);
 
 	mehci->resume_status = 0;
 	resume_thread = kthread_run(msm_hsic_resume_thread,
@@ -1351,6 +1370,9 @@
 
 	spin_unlock_irq(&ehci->lock);
 
+	if (pdata->resume_gpio)
+		gpio_direction_output(pdata->resume_gpio, 0);
+
 	return 0;
 }
 
@@ -1781,6 +1803,11 @@
 		res_gpio = 0;
 	pdata->data = res_gpio;
 
+	res_gpio = of_get_named_gpio(node, "hsic,resume-gpio", 0);
+	if (res_gpio < 0)
+		res_gpio = 0;
+	pdata->resume_gpio = res_gpio;
+
 	pdata->ignore_cal_pad_config = of_property_read_bool(node,
 					"hsic,ignore-cal-pad-config");
 	of_property_read_u32(node, "hsic,strobe-pad-offset",
@@ -2099,6 +2126,10 @@
 	destroy_workqueue(ehci_wq);
 
 	msm_hsic_config_gpios(mehci, 0);
+
+	if (pdata && pdata->resume_gpio)
+		gpio_free(pdata->resume_gpio);
+
 	msm_hsic_init_vddcx(mehci, 0);
 	msm_hsic_init_gdsc(mehci, 0);
 
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index c5943c9..ea45a8c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -406,6 +406,9 @@
 	struct msm_bus_scale_pdata *bus_scale_table;
 	unsigned log2_irq_thresh;
 
+	/* gpio used to resume peripheral */
+	unsigned resume_gpio;
+
 	/*swfi latency is required while driving resume on to the bus */
 	u32 swfi_latency;