wcnss: Configuration of Iris 5-wire GPIOs by WCNSS driver

GPIOs tied to 5-wire interface to Iris must be controlled from within
WCNSS Platform Driver. This allows the platform driver to free the GPIO
resources and park them in a suspend mode (when appropriate) for power
savings

Change-Id: Ieaaf636f87e82e1b2c5b2ffa16b3a5d9e1c6fc33
Acked-by: Kumar Anand <kanand@qca.qualcomm.com>
Signed-off-by: Ankur Nandwani <ankurn@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 97f1d3a..9610e33 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -463,7 +463,7 @@
 static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv  = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.pull = GPIOMUX_PULL_UP,
 };
 
 static struct gpiomux_setting wcnss_5wire_active_cfg = {
@@ -2099,6 +2099,12 @@
 		.name	= "wcnss_mmio",
 		.flags	= IORESOURCE_MEM,
 	},
+	{
+		.start	= 84,
+		.end	= 88,
+		.name	= "wcnss_gpios_5wire",
+		.flags	= IORESOURCE_IO,
+	},
 };
 
 static struct qcom_wcnss_opts qcom_wcnss_pdata = {
@@ -3762,29 +3768,6 @@
 	},
 };
 
-static void msm8960_wcnss_init(void)
-{
-	int i, ret, j;
-
-	for (i = 0; i < ARRAY_SIZE(wcnss_5wire_interface); i++) {
-		ret = gpio_request(wcnss_5wire_interface[i].gpio,
-				"wcnss_5_wire");
-		if (ret) {
-			pr_err("wcnss_5_wire gpio %d failed: %d\n",
-				wcnss_5wire_interface[i].gpio, ret);
-			goto fail;
-		}
-	}
-
-	pr_info("%s: Iris 5-wire gpios configured\n", __func__);
-
-	return;
-
-fail:
-	for (j = 0; j < i; j++)
-		gpio_free(wcnss_5wire_interface[j].gpio);
-}
-
 #ifdef CONFIG_KS8851
 static int ethernet_init(void)
 {
@@ -4206,7 +4189,6 @@
 	if (machine_is_msm8960_liquid())
 		mxt_init_hw_liquid();
 	register_i2c_devices();
-	msm8960_wcnss_init();
 	msm_fb_add_devices();
 	slim_register_board_info(msm_slim_devices,
 		ARRAY_SIZE(msm_slim_devices));
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index d850a5e..e6945d5 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -20,6 +20,7 @@
 #include <linux/platform_data/qcom_wcnss_device.h>
 #include <linux/workqueue.h>
 #include <linux/jiffies.h>
+#include <linux/gpio.h>
 #include <mach/peripheral-loader.h>
 #include "wcnss_riva.h"
 
@@ -40,6 +41,7 @@
 	struct resource	*mmio_res;
 	struct resource	*tx_irq_res;
 	struct resource	*rx_irq_res;
+	struct resource	*gpios_5wire;
 	const struct dev_pm_ops *pm_ops;
 	int             smd_channel_ready;
 	struct wcnss_wlan_config wlan_config;
@@ -55,6 +57,31 @@
 		WCNSS_WLAN_SWITCH_OFF);
 }
 
+static int
+wcnss_gpios_config(struct resource *gpios_5wire, bool enable)
+{
+	int i, j;
+	int rc = 0;
+
+	for (i = gpios_5wire->start; i <= gpios_5wire->end; i++) {
+		if (enable) {
+			rc = gpio_request(i, gpios_5wire->name);
+			if (rc) {
+				pr_err("WCNSS gpio_request %d err %d\n", i, rc);
+				goto fail;
+			}
+		} else
+			gpio_free(i);
+	}
+
+	return rc;
+
+fail:
+	for (j = i-1; j >= gpios_5wire->start; j--)
+		gpio_free(j);
+	return rc;
+}
+
 static int __devinit
 wcnss_wlan_ctrl_probe(struct platform_device *pdev)
 {
@@ -189,6 +216,23 @@
 		has_48mhz_xo = pdata->has_48mhz_xo;
 	penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
 
+	penv->gpios_5wire = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							"wcnss_gpios_5wire");
+
+	/* allocate 5-wire GPIO resources */
+	if (!penv->gpios_5wire) {
+		dev_err(&pdev->dev, "insufficient IO resources\n");
+		ret = -ENOENT;
+		goto fail_gpio_res;
+	}
+
+	/* Configure 5 wire GPIOs */
+	ret = wcnss_gpios_config(penv->gpios_5wire, true);
+	if (ret) {
+		dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
+		goto fail_gpio_res;
+	}
+
 	/* power up the WCNSS */
 	ret = wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
 					WCNSS_WLAN_SWITCH_ON);
@@ -229,6 +273,8 @@
 	wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
 				WCNSS_WLAN_SWITCH_OFF);
 fail_power:
+	wcnss_gpios_config(penv->gpios_5wire, false);
+fail_gpio_res:
 	kfree(penv);
 	penv = NULL;
 	return ret;