msm: 8960: add ath6kl_wlan_power function to control AR6004 gpio

Add necessary functions for AR6004 to control BT related GPIO.
This change will only be used by AR6004

Change-Id: Ia3b7d11f41e836036f5807a2a10265c55741b1b0
Signed-off-by: Ming-yi Lin <mylin@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 1771bb9..fe37f2a 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -449,6 +449,13 @@
 		},
 	},
 	{
+		.gpio      = 26,	/* GSBI6 WLAN_PWD_L for AR6004 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi6_suspended_cfg,
+			[GPIOMUX_ACTIVE] = &gsbi6_active_cfg,
+		},
+	},
+	{
 		.gpio      = 27,        /* GSBI6 BT_INT2AP_N for AR3002 */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gsbi6_suspended_cfg,
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index 67f44aa..ded5bad 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -327,9 +327,11 @@
 #endif
 	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
 	.pin_data	= &mmc_slot_pin_data[SDCC3],
+#ifndef CONFIG_MMC_MSM_SDC3_POLLING
 	.status_gpio	= PM8921_GPIO_PM_TO_SYS(26),
 	.status_irq	= PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
 	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
 	.is_status_gpio_active_low = true,
 	.xpc_cap	= 1,
 	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 7e96edf..cdd5a39 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -103,6 +103,11 @@
 #include "pm-boot.h"
 #include "msm_watchdog.h"
 
+#if defined(CONFIG_BT) && defined(CONFIG_BT_HCIUART_ATH3K)
+#include <linux/wlan_plat.h>
+#include <linux/mutex.h>
+#endif
+
 static struct platform_device msm_fm_platform_init = {
 	.name = "iris_fm",
 	.id   = -1,
@@ -2602,6 +2607,76 @@
 #endif
 
 #if defined(CONFIG_BT) && defined(CONFIG_BT_HCIUART_ATH3K)
+enum WLANBT_STATUS {
+	WLANOFF_BTOFF = 1,
+	WLANOFF_BTON,
+	WLANON_BTOFF,
+	WLANON_BTON
+};
+
+static DEFINE_MUTEX(ath_wlanbt_mutex);
+static int gpio_wlan_sys_rest_en = 26;
+static int ath_wlanbt_status = WLANOFF_BTOFF;
+
+static int ath6kl_power_control(int on)
+{
+	int rc;
+
+	if (on) {
+		rc = gpio_request(gpio_wlan_sys_rest_en, "wlan sys_rst_n");
+		if (rc) {
+			pr_err("%s: unable to request gpio %d (%d)\n",
+				__func__, gpio_wlan_sys_rest_en, rc);
+			return rc;
+		}
+		rc = gpio_direction_output(gpio_wlan_sys_rest_en, 0);
+		msleep(200);
+		rc = gpio_direction_output(gpio_wlan_sys_rest_en, 1);
+		msleep(100);
+	} else {
+		gpio_set_value(gpio_wlan_sys_rest_en, 0);
+		rc = gpio_direction_input(gpio_wlan_sys_rest_en);
+		msleep(100);
+		gpio_free(gpio_wlan_sys_rest_en);
+	}
+	return 0;
+};
+
+static int ath6kl_wlan_power(int on)
+{
+	int ret = 0;
+
+	mutex_lock(&ath_wlanbt_mutex);
+	if (on) {
+		if (ath_wlanbt_status == WLANOFF_BTOFF) {
+			ret = ath6kl_power_control(1);
+			ath_wlanbt_status = WLANON_BTOFF;
+		} else if (ath_wlanbt_status == WLANOFF_BTON)
+			ath_wlanbt_status = WLANON_BTON;
+	} else {
+		if (ath_wlanbt_status == WLANON_BTOFF) {
+			ret = ath6kl_power_control(0);
+			ath_wlanbt_status = WLANOFF_BTOFF;
+		} else if (ath_wlanbt_status == WLANON_BTON)
+			ath_wlanbt_status = WLANOFF_BTON;
+	}
+	mutex_unlock(&ath_wlanbt_mutex);
+	pr_debug("%s on= %d, wlan_status= %d\n",
+		__func__, on, ath_wlanbt_status);
+	return ret;
+};
+
+static struct wifi_platform_data ath6kl_wifi_control = {
+	.set_power      = ath6kl_wlan_power,
+};
+
+static struct platform_device msm_wlan_power_device = {
+	.name = "ath6kl_power",
+	.dev            = {
+		.platform_data = &ath6kl_wifi_control,
+	},
+};
+
 static struct resource bluesleep_resources[] = {
 	{
 		.name   = "gpio_host_wake",
@@ -2634,50 +2709,54 @@
 	.name = "bt_power",
 };
 
-int gpio_bt_sys_rest_en = 28;
+static int gpio_bt_sys_rest_en = 28;
 
 static int bluetooth_power(int on)
 {
 	int rc;
 
-	pr_debug("%s on= %d\n", __func__, on);
-
+	mutex_lock(&ath_wlanbt_mutex);
 	if (on) {
+		if (ath_wlanbt_status == WLANOFF_BTOFF) {
+			ath6kl_power_control(1);
+			ath_wlanbt_status = WLANOFF_BTON;
+		} else if (ath_wlanbt_status == WLANON_BTOFF)
+			ath_wlanbt_status = WLANON_BTON;
+
 		rc = gpio_request(gpio_bt_sys_rest_en, "bt sys_rst_n");
 		if (rc) {
 			pr_err("%s: unable to request gpio %d (%d)\n",
 				__func__, gpio_bt_sys_rest_en, rc);
-			goto out;
+			mutex_unlock(&ath_wlanbt_mutex);
+			return rc;
 		}
 		rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
-		if (rc) {
-			pr_err("%s: Unable to set gpio %d direction\n",
-				__func__, gpio_bt_sys_rest_en);
-			goto free_gpio;
-		}
+		msleep(20);
+		rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
 		msleep(100);
-		gpio_set_value(gpio_bt_sys_rest_en, 1);
-		msleep(100);
-		goto out;
 	} else {
 		gpio_set_value(gpio_bt_sys_rest_en, 0);
 		rc = gpio_direction_input(gpio_bt_sys_rest_en);
 		msleep(100);
-	}
+		gpio_free(gpio_bt_sys_rest_en);
 
-free_gpio:
-	gpio_free(gpio_bt_sys_rest_en);
-out:
-	return rc;
-}
+		if (ath_wlanbt_status == WLANOFF_BTON) {
+			ath6kl_power_control(0);
+			ath_wlanbt_status = WLANOFF_BTOFF;
+		} else if (ath_wlanbt_status == WLANON_BTON)
+			ath_wlanbt_status = WLANON_BTOFF;
+	}
+	mutex_unlock(&ath_wlanbt_mutex);
+	pr_debug("%s on= %d, wlan_status= %d\n",
+		__func__, on, ath_wlanbt_status);
+	return 0;
+};
 
 static void __init bt_power_init(void)
 {
-	pr_debug("%s enter\n", __func__);
 	msm_bt_power_device.dev.platform_data = &bluetooth_power;
-
 	return;
-}
+};
 #else
 #define bt_power_init(x) do {} while (0)
 #endif
@@ -2703,6 +2782,7 @@
 #if defined(CONFIG_BT) && defined(CONFIG_BT_HCIUART_ATH3K)
 	&msm_bluesleep_device,
 	&msm_bt_power_device,
+	&msm_wlan_power_device,
 #endif
 #if defined(CONFIG_QSEECOM)
 	&qseecom_device,
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 0c3f994..da38122 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -500,6 +500,10 @@
 	help
 	  Select Y to enable Slot 3.
 
+config MMC_MSM_SDC3_POLLING
+	boolean "Qualcomm SDC3 support"
+	depends on MMC_MSM
+
 config MMC_MSM_SDC3_8_BIT_SUPPORT
 	boolean "Qualcomm SDC3 8bit support"
 	depends on MMC_MSM_SDC3_SUPPORT