Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/drivers/net/wireless/libra/Makefile b/drivers/net/wireless/libra/Makefile
new file mode 100644
index 0000000..3c606ba
--- /dev/null
+++ b/drivers/net/wireless/libra/Makefile
@@ -0,0 +1,14 @@
+
+# Makefile for wlan sdio if driver
+
+librasdioif-objs += libra_sdioif.o
+
+ifdef CONFIG_ARCH_MSM8X60
+	librasdioif-objs += qcomwlan_pwrif.o
+endif
+
+ifdef CONFIG_ARCH_MSM7X27A
+	librasdioif-objs += qcomwlan7x27a_pwrif.o
+endif
+
+obj-$(CONFIG_LIBRA_SDIOIF) += librasdioif.o
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
new file mode 100644
index 0000000..3955642
--- /dev/null
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -0,0 +1,481 @@
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/libra_sdioif.h>
+#include <linux/delay.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+/* Libra SDIO function device */
+static struct sdio_func *libra_sdio_func;
+static struct mmc_host *libra_mmc_host;
+static int libra_mmc_host_index;
+
+/* SDIO Card ID / Device ID */
+static unsigned short  libra_sdio_card_id;
+
+static suspend_handler_t *libra_suspend_hldr;
+static resume_handler_t *libra_resume_hldr;
+
+/**
+ * libra_sdio_configure() - Function to configure the SDIO device param
+ * @libra_sdio_rxhandler    Rx handler
+ * @func_drv_fn             Function driver function for special setup
+ * @funcdrv_timeout         Function Enable timeout
+ * @blksize                 Block size
+ *
+ * Configure SDIO device, enable function and set block size
+ */
+int libra_sdio_configure(sdio_irq_handler_t libra_sdio_rxhandler,
+	void  (*func_drv_fn)(int *status),
+	unsigned int funcdrv_timeout, unsigned int blksize)
+{
+	int err_ret = 0;
+	struct sdio_func *func = libra_sdio_func;
+
+	if (libra_sdio_func == NULL) {
+		printk(KERN_ERR "%s: Error SDIO card not detected\n", __func__);
+		goto cfg_error;
+	}
+
+	sdio_claim_host(func);
+
+	/* Currently block sizes are set here. */
+	func->max_blksize = blksize;
+	if (sdio_set_block_size(func, blksize)) {
+		printk(KERN_ERR "%s: Unable to set the block size.\n",
+				__func__);
+		sdio_release_host(func);
+		goto cfg_error;
+	}
+
+	/* Function driver specific configuration. */
+	if (func_drv_fn) {
+		(*func_drv_fn)(&err_ret);
+		if (err_ret) {
+			printk(KERN_ERR "%s: function driver provided configure function error=%d\n",
+				__func__, err_ret);
+			sdio_release_host(func);
+			goto cfg_error;
+		}
+	}
+
+	/* We set this based on the function card. */
+	func->enable_timeout = funcdrv_timeout;
+	err_ret = sdio_enable_func(func);
+	if (err_ret != 0) {
+		printk(KERN_ERR "%s: Unable to enable function %d\n",
+				__func__, err_ret);
+		sdio_release_host(func);
+		goto cfg_error;
+	}
+
+	if (sdio_claim_irq(func, libra_sdio_rxhandler)) {
+		sdio_disable_func(func);
+		printk(KERN_ERR "%s: Unable to claim irq.\n", __func__);
+		sdio_release_host(func);
+		goto cfg_error;
+	}
+
+	sdio_release_host(func);
+
+	return 0;
+
+cfg_error:
+	return -1;
+
+}
+EXPORT_SYMBOL(libra_sdio_configure);
+
+int libra_sdio_configure_suspend_resume(
+		suspend_handler_t *libra_sdio_suspend_hdlr,
+		resume_handler_t *libra_sdio_resume_hdlr)
+{
+	libra_suspend_hldr = libra_sdio_suspend_hdlr;
+	libra_resume_hldr = libra_sdio_resume_hdlr;
+	return 0;
+}
+EXPORT_SYMBOL(libra_sdio_configure_suspend_resume);
+
+/*
+ * libra_sdio_deconfigure() - Function to reset the SDIO device param
+ */
+void libra_sdio_deconfigure(struct sdio_func *func)
+{
+	if (NULL == libra_sdio_func)
+		return;
+
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+}
+EXPORT_SYMBOL(libra_sdio_deconfigure);
+
+int libra_enable_sdio_irq(struct sdio_func *func, u8 enable)
+{
+	if (libra_mmc_host && libra_mmc_host->ops &&
+			libra_mmc_host->ops->enable_sdio_irq) {
+		libra_mmc_host->ops->enable_sdio_irq(libra_mmc_host, enable);
+		return 0;
+	}
+
+	printk(KERN_ERR "%s: Could not enable disable irq\n", __func__);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(libra_enable_sdio_irq);
+
+int libra_disable_sdio_irq_capability(struct sdio_func *func, u8 disable)
+{
+	if (libra_mmc_host) {
+		if (disable)
+			libra_mmc_host->caps &= ~MMC_CAP_SDIO_IRQ;
+		else
+			libra_mmc_host->caps |= MMC_CAP_SDIO_IRQ;
+		return 0;
+	}
+	printk(KERN_ERR "%s: Could not change sdio capabilities to polling\n",
+			__func__);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(libra_disable_sdio_irq_capability);
+
+/*
+ * libra_sdio_release_irq() - Function to release IRQ
+ */
+void libra_sdio_release_irq(struct sdio_func *func)
+{
+	if (NULL == libra_sdio_func)
+		return;
+
+	sdio_release_irq(func);
+}
+EXPORT_SYMBOL(libra_sdio_release_irq);
+
+/*
+ * libra_sdio_disable_func() - Function to disable sdio func
+ */
+void libra_sdio_disable_func(struct sdio_func *func)
+{
+	if (NULL == libra_sdio_func)
+		return;
+
+	sdio_disable_func(func);
+}
+EXPORT_SYMBOL(libra_sdio_disable_func);
+
+/*
+ * Return the SDIO Function device
+ */
+struct sdio_func *libra_getsdio_funcdev(void)
+{
+	return libra_sdio_func;
+}
+EXPORT_SYMBOL(libra_getsdio_funcdev);
+
+/*
+ * Set function driver as the private data for the function device
+ */
+void libra_sdio_setprivdata(struct sdio_func *sdio_func_dev,
+		void *padapter)
+{
+	if (NULL == libra_sdio_func)
+		return;
+
+	sdio_set_drvdata(sdio_func_dev, padapter);
+}
+EXPORT_SYMBOL(libra_sdio_setprivdata);
+
+/*
+ * Return private data of the function device.
+ */
+void *libra_sdio_getprivdata(struct sdio_func *sdio_func_dev)
+{
+	return sdio_get_drvdata(sdio_func_dev);
+}
+EXPORT_SYMBOL(libra_sdio_getprivdata);
+
+/*
+ * Function driver claims the SDIO device
+ */
+void libra_claim_host(struct sdio_func *sdio_func_dev,
+		pid_t *curr_claimed, pid_t current_pid, atomic_t *claim_count)
+{
+	if (NULL == libra_sdio_func)
+		return;
+
+	if (*curr_claimed == current_pid) {
+		atomic_inc(claim_count);
+		return;
+	}
+
+	/* Go ahead and claim the host if not locked by anybody. */
+	sdio_claim_host(sdio_func_dev);
+
+	*curr_claimed = current_pid;
+	atomic_inc(claim_count);
+
+}
+EXPORT_SYMBOL(libra_claim_host);
+
+/*
+ * Function driver releases the SDIO device
+ */
+void libra_release_host(struct sdio_func *sdio_func_dev,
+		pid_t *curr_claimed, pid_t current_pid, atomic_t *claim_count)
+{
+
+	if (NULL == libra_sdio_func)
+		return;
+
+	if (*curr_claimed != current_pid) {
+		/* Dont release  */
+		return;
+	}
+
+	atomic_dec(claim_count);
+	if (atomic_read(claim_count) == 0) {
+		*curr_claimed = 0;
+		sdio_release_host(sdio_func_dev);
+	}
+}
+EXPORT_SYMBOL(libra_release_host);
+
+void libra_sdiocmd52(struct sdio_func *sdio_func_dev, unsigned int addr,
+	u8 *byte_var, int write, int *err_ret)
+{
+	if (write)
+		sdio_writeb(sdio_func_dev, byte_var[0], addr, err_ret);
+	else
+		byte_var[0] = sdio_readb(sdio_func_dev, addr, err_ret);
+}
+EXPORT_SYMBOL(libra_sdiocmd52);
+
+u8 libra_sdio_readsb(struct sdio_func *func, void *dst,
+	unsigned int addr, int count)
+{
+	return sdio_readsb(func, dst, addr, count);
+}
+EXPORT_SYMBOL(libra_sdio_readsb);
+
+int libra_sdio_memcpy_fromio(struct sdio_func *func,
+		void *dst, unsigned int addr, int count)
+{
+	return sdio_memcpy_fromio(func, dst, addr, count);
+}
+EXPORT_SYMBOL(libra_sdio_memcpy_fromio);
+
+int libra_sdio_writesb(struct sdio_func *func,
+		unsigned int addr, void *src, int count)
+{
+	return sdio_writesb(func, addr, src, count);
+}
+EXPORT_SYMBOL(libra_sdio_writesb);
+
+int libra_sdio_memcpy_toio(struct sdio_func *func,
+	unsigned int addr, void *src, int count)
+{
+	return sdio_memcpy_toio(func, addr, src, count);
+}
+EXPORT_SYMBOL(libra_sdio_memcpy_toio);
+
+int libra_detect_card_change(void)
+{
+	if (libra_mmc_host) {
+		if (!strcmp(libra_mmc_host->class_dev.class->name, "mmc_host")
+			&& (libra_mmc_host_index == libra_mmc_host->index)) {
+			mmc_detect_change(libra_mmc_host, 0);
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Could not trigger card change\n", __func__);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(libra_detect_card_change);
+
+int libra_sdio_enable_polling(void)
+{
+	if (libra_mmc_host) {
+		if (!strcmp(libra_mmc_host->class_dev.class->name, "mmc_host")
+			&& (libra_mmc_host_index == libra_mmc_host->index)) {
+			libra_mmc_host->caps |= MMC_CAP_NEEDS_POLL;
+			mmc_detect_change(libra_mmc_host, 0);
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Could not trigger SDIO scan\n", __func__);
+	return -1;
+}
+EXPORT_SYMBOL(libra_sdio_enable_polling);
+
+void libra_sdio_set_clock(struct sdio_func *func, unsigned int clk_freq)
+{
+    struct mmc_host *host = func->card->host;
+    host->ios.clock = clk_freq;
+    host->ops->set_ios(host, &host->ios);
+
+}
+EXPORT_SYMBOL(libra_sdio_set_clock);
+
+/*
+ * API to get SDIO Device Card ID
+ */
+void libra_sdio_get_card_id(struct sdio_func *func, unsigned short *card_id)
+{
+	if (card_id)
+		*card_id = libra_sdio_card_id;
+}
+EXPORT_SYMBOL(libra_sdio_get_card_id);
+
+/*
+ * SDIO Probe
+ */
+static int libra_sdio_probe(struct sdio_func *func,
+		const struct sdio_device_id *sdio_dev_id)
+{
+	libra_mmc_host = func->card->host;
+	libra_mmc_host_index = libra_mmc_host->index;
+	libra_sdio_func = func;
+	libra_sdio_card_id = sdio_dev_id->device;
+
+	printk(KERN_INFO "%s: success with block size of %d device_id=0x%x\n",
+		__func__,
+		func->cur_blksize,
+		sdio_dev_id->device);
+
+	/* Turn off SDIO polling from now on */
+	libra_mmc_host->caps &= ~MMC_CAP_NEEDS_POLL;
+	return 0;
+}
+
+static void libra_sdio_remove(struct sdio_func *func)
+{
+	libra_sdio_func = NULL;
+
+	printk(KERN_INFO "%s : Module removed.\n", __func__);
+}
+
+#ifdef CONFIG_PM
+static int libra_sdio_suspend(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	int ret = 0;
+
+	ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+
+	if (ret) {
+		printk(KERN_ERR "%s: Error Host doesn't support the keep power capability\n" ,
+			__func__);
+		return ret;
+	}
+	if (libra_suspend_hldr) {
+		/* Disable SDIO IRQ when driver is being suspended */
+		libra_enable_sdio_irq(func, 0);
+		ret = libra_suspend_hldr(func);
+		if (ret) {
+			printk(KERN_ERR
+			"%s: Libra driver is not able to suspend\n" , __func__);
+			/* Error - Restore SDIO IRQ */
+			libra_enable_sdio_irq(func, 1);
+			return ret;
+		}
+	}
+
+
+	return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+}
+
+static int libra_sdio_resume(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+
+	if (libra_resume_hldr) {
+		libra_resume_hldr(func);
+		/* Restore SDIO IRQ */
+		libra_enable_sdio_irq(func, 1);
+	}
+
+	return 0;
+}
+#else
+#define libra_sdio_suspend 0
+#define libra_sdio_resume 0
+#endif
+
+static struct sdio_device_id libra_sdioid[] = {
+    {.class = 0, .vendor = LIBRA_MAN_ID,  .device = LIBRA_REV_1_0_CARD_ID},
+    {.class = 0, .vendor = VOLANS_MAN_ID, .device = VOLANS_REV_2_0_CARD_ID},
+    {}
+};
+
+static const struct dev_pm_ops libra_sdio_pm_ops = {
+    .suspend = libra_sdio_suspend,
+    .resume = libra_sdio_resume,
+};
+
+static struct sdio_driver libra_sdiofn_driver = {
+    .name      = "libra_sdiofn",
+    .id_table  = libra_sdioid,
+    .probe     = libra_sdio_probe,
+    .remove    = libra_sdio_remove,
+    .drv.pm    = &libra_sdio_pm_ops,
+};
+
+static int __init libra_sdioif_init(void)
+{
+	libra_sdio_func = NULL;
+	libra_mmc_host = NULL;
+	libra_mmc_host_index = -1;
+	libra_suspend_hldr = NULL;
+	libra_resume_hldr = NULL;
+
+	sdio_register_driver(&libra_sdiofn_driver);
+
+	printk(KERN_INFO "%s: Loaded Successfully\n", __func__);
+
+	return 0;
+}
+
+static void __exit libra_sdioif_exit(void)
+{
+	unsigned int attempts = 0;
+
+	if (!libra_detect_card_change()) {
+		do {
+			++attempts;
+			msleep(500);
+		} while (libra_sdio_func != NULL && attempts < 3);
+	}
+
+	if (libra_sdio_func != NULL)
+		printk(KERN_ERR "%s: Card removal not detected\n", __func__);
+
+	sdio_unregister_driver(&libra_sdiofn_driver);
+
+	libra_sdio_func = NULL;
+	libra_mmc_host = NULL;
+	libra_mmc_host_index = -1;
+
+	printk(KERN_INFO "%s: Unloaded Successfully\n", __func__);
+}
+
+module_init(libra_sdioif_init);
+module_exit(libra_sdioif_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("WLAN SDIODriver");
diff --git a/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c b/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c
new file mode 100644
index 0000000..ca2680f
--- /dev/null
+++ b/drivers/net/wireless/libra/qcomwlan7x27a_pwrif.c
@@ -0,0 +1,172 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <mach/vreg.h>
+#include <linux/gpio.h>
+#include <mach/rpc_pmapp.h>
+#include <linux/err.h>
+#include <linux/qcomwlan7x27a_pwrif.h>
+
+#define WLAN_GPIO_EXT_POR_N     134
+
+static const char *id = "WLAN";
+
+enum {
+	WLAN_VREG_L17 = 0,
+	WLAN_VREG_S3,
+	WLAN_VREG_TCXO_L11,
+	WLAN_VREG_L19,
+	WLAN_VREG_L5,
+	WLAN_VREG_L6
+};
+
+struct wlan_vreg_info {
+	const char *vreg_id;
+	unsigned int vreg_level;
+	unsigned int pmapp_id;
+	unsigned int is_vreg_pin_controlled;
+	struct vreg *vreg;
+};
+
+
+static struct wlan_vreg_info vreg_info[] = {
+	{"bt", 3050, 56, 0, NULL},
+	{"msme1", 1800, 2, 0, NULL},
+	{"wlan_tcx0", 1800, 53, 0, NULL},
+	{"wlan4", 1200, 57, 0, NULL},
+	{"wlan2", 1350, 45, 0, NULL},
+	{"wlan3", 1200, 51, 0, NULL} };
+
+int chip_power_qrf6285(bool on)
+{
+	int rc = 0, index = 0;
+
+	if (on) {
+		rc = gpio_request(WLAN_GPIO_EXT_POR_N, "WLAN_DEEP_SLEEP_N");
+
+		if (rc) {
+			pr_err("WLAN reset GPIO %d request failed %d\n",
+			WLAN_GPIO_EXT_POR_N, rc);
+			goto fail;
+		}
+		rc = gpio_direction_output(WLAN_GPIO_EXT_POR_N, 1);
+		if (rc < 0) {
+			pr_err("WLAN reset GPIO %d set direction failed %d\n",
+			WLAN_GPIO_EXT_POR_N, rc);
+			goto fail_gpio_dir_out;
+		}
+	} else {
+		gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
+		gpio_free(WLAN_GPIO_EXT_POR_N);
+	}
+
+
+	for (index = 0; index < ARRAY_SIZE(vreg_info); index++) {
+		vreg_info[index].vreg = vreg_get(NULL,
+						vreg_info[index].vreg_id);
+		if (IS_ERR(vreg_info[index].vreg)) {
+			pr_err("%s:%s vreg get failed %ld\n",
+				__func__, vreg_info[index].vreg_id,
+				PTR_ERR(vreg_info[index].vreg));
+			rc = PTR_ERR(vreg_info[index].vreg);
+			if (on)
+				goto vreg_fail;
+			else
+				continue;
+		}
+		if (on) {
+			rc = vreg_set_level(vreg_info[index].vreg,
+					 vreg_info[index].vreg_level);
+			if (rc) {
+				pr_err("%s:%s vreg set level failed %d\n",
+					__func__, vreg_info[index].vreg_id, rc);
+				goto vreg_fail;
+			}
+			if (vreg_info[index].is_vreg_pin_controlled) {
+				rc = pmapp_vreg_pincntrl_vote(id,
+					 vreg_info[index].pmapp_id,
+					 PMAPP_CLOCK_ID_A0, 1);
+				if (rc) {
+					pr_err("%s:%s pmapp_vreg_pincntrl_vote"
+						" for enable failed %d\n",
+						__func__,
+						vreg_info[index].vreg_id, rc);
+					goto vreg_fail;
+				}
+			} else {
+				rc = vreg_enable(vreg_info[index].vreg);
+				if (rc) {
+					pr_err("%s:%s vreg enable failed %d\n",
+						__func__,
+						vreg_info[index].vreg_id, rc);
+					goto vreg_fail;
+				}
+			}
+
+			if (WLAN_VREG_TCXO_L11 == index) {
+				/*
+				 * Configure TCXO to be slave to
+				 * WLAN_CLK_PWR_REQ
+`				 */
+				rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
+						PMAPP_CLOCK_VOTE_PIN_CTRL);
+				if (rc) {
+					pr_err("%s: Configuring TCXO to Pin"
+					" controllable failed %d\n",
+							 __func__, rc);
+					goto vreg_clock_vote_fail;
+				}
+			}
+
+		} else {
+
+			if (vreg_info[index].is_vreg_pin_controlled) {
+				rc = pmapp_vreg_pincntrl_vote(id,
+						 vreg_info[index].pmapp_id,
+						 PMAPP_CLOCK_ID_A0, 0);
+				if (rc) {
+					pr_err("%s:%s pmapp_vreg_pincntrl_vote"
+						" for disable failed %d\n",
+						__func__,
+						vreg_info[index].vreg_id, rc);
+				}
+			} else {
+				rc = vreg_disable(vreg_info[index].vreg);
+				if (rc) {
+					pr_err("%s:%s vreg disable failed %d\n",
+						__func__,
+						vreg_info[index].vreg_id, rc);
+				}
+			}
+		}
+	}
+	return 0;
+vreg_fail:
+	index--;
+vreg_clock_vote_fail:
+	while (index > 0) {
+		rc = vreg_disable(vreg_info[index].vreg);
+		if (rc) {
+			pr_err("%s:%s vreg disable failed %d\n",
+				__func__, vreg_info[index].vreg_id, rc);
+		}
+		index--;
+	}
+	if (!on)
+		goto fail;
+fail_gpio_dir_out:
+	gpio_free(WLAN_GPIO_EXT_POR_N);
+fail:
+	return rc;
+}
+EXPORT_SYMBOL(chip_power_qrf6285);
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
new file mode 100644
index 0000000..bb5e135
--- /dev/null
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/qcomwlan_pwrif.h>
+
+#define GPIO_WLAN_DEEP_SLEEP_N  230
+#define WLAN_RESET_OUT          1
+#define WLAN_RESET              0
+
+static const char *id = "WLAN";
+
+/**
+ * vos_chip_power_qrf8615() - WLAN Power Up Seq for WCN1314 rev 2.0 on QRF 8615
+ * @on - Turn WLAN ON/OFF (1 or 0)
+ *
+ * Power up/down WLAN by turning on/off various regs and asserting/deasserting
+ * Power-on-reset pin. Also, put XO A0 buffer as slave to wlan_clk_pwr_req while
+ * turning ON WLAN and vice-versa.
+ *
+ * This function returns 0 on success or a non-zero value on failure.
+ */
+int vos_chip_power_qrf8615(int on)
+{
+	static char wlan_on;
+	static const char *vregs_qwlan_name[] = {
+		"8058_l20",
+		"8058_l8",
+		"8901_s4",
+		"8901_lvs1",
+		"8901_l0",
+		"8058_s2",
+		"8058_s1",
+	};
+	static const int vregs_qwlan_val_min[] = {
+		1800000,
+		3050000,
+		1225000,
+		0,
+		1200000,
+		1300000,
+		500000,
+	};
+	static const int vregs_qwlan_val_max[] = {
+		1800000,
+		3050000,
+		1225000,
+		0,
+		1200000,
+		1300000,
+		1250000,
+	};
+	static const bool vregs_is_pin_controlled[] = {
+		1,
+		1,
+		0,
+		0,
+		1,
+		1,
+		0,
+	};
+	static struct regulator *vregs_qwlan[ARRAY_SIZE(vregs_qwlan_name)];
+	static struct msm_xo_voter *wlan_clock;
+	int ret, i, rc = 0;
+
+	/* WLAN RESET and CLK settings */
+	if (on && !wlan_on) {
+		/*
+		 * Program U12 GPIO expander pin IO1 to de-assert (drive 0)
+		 * WLAN_EXT_POR_N to put WLAN in reset
+		 */
+		rc = gpio_request(GPIO_WLAN_DEEP_SLEEP_N, "WLAN_DEEP_SLEEP_N");
+		if (rc) {
+			pr_err("WLAN reset GPIO %d request failed\n",
+					GPIO_WLAN_DEEP_SLEEP_N);
+			goto fail;
+		}
+		rc = gpio_direction_output(GPIO_WLAN_DEEP_SLEEP_N,
+				WLAN_RESET_OUT);
+		if (rc < 0) {
+			pr_err("WLAN reset GPIO %d set output direction failed",
+					GPIO_WLAN_DEEP_SLEEP_N);
+			goto fail_gpio_dir_out;
+		}
+
+		/* Configure TCXO to be slave to WLAN_CLK_PWR_REQ */
+		if (wlan_clock == NULL) {
+			wlan_clock = msm_xo_get(MSM_XO_TCXO_A0, id);
+			if (IS_ERR(wlan_clock)) {
+				pr_err("Failed to get TCXO_A0 voter (%ld)\n",
+						PTR_ERR(wlan_clock));
+				goto fail_gpio_dir_out;
+			}
+		}
+
+		rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_PIN_CTRL);
+		if (rc < 0) {
+			pr_err("Configuring TCXO to Pin controllable failed"
+					"(%d)\n", rc);
+			goto fail_xo_mode_vote;
+		}
+	} else if (!on && wlan_on) {
+		if (wlan_clock != NULL)
+			msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
+		gpio_set_value_cansleep(GPIO_WLAN_DEEP_SLEEP_N, WLAN_RESET);
+		gpio_free(GPIO_WLAN_DEEP_SLEEP_N);
+	}
+
+	/* WLAN VREG settings */
+	for (i = 0; i < ARRAY_SIZE(vregs_qwlan_name); i++) {
+		if (vregs_qwlan[i] == NULL) {
+			vregs_qwlan[i] = regulator_get(NULL,
+					vregs_qwlan_name[i]);
+			if (IS_ERR(vregs_qwlan[i])) {
+				pr_err("regulator get of %s failed (%ld)\n",
+						vregs_qwlan_name[i],
+						PTR_ERR(vregs_qwlan[i]));
+				rc = PTR_ERR(vregs_qwlan[i]);
+				goto vreg_get_fail;
+			}
+			if (vregs_qwlan_val_min[i] || vregs_qwlan_val_max[i]) {
+				rc = regulator_set_voltage(vregs_qwlan[i],
+						vregs_qwlan_val_min[i],
+						vregs_qwlan_val_max[i]);
+				if (rc) {
+					pr_err("regulator_set_voltage(%s) failed\n",
+							vregs_qwlan_name[i]);
+					goto vreg_fail;
+				}
+			}
+			/* vote for pin control (if needed) */
+			if (vregs_is_pin_controlled[i]) {
+				rc = regulator_set_mode(vregs_qwlan[i],
+						REGULATOR_MODE_IDLE);
+				if (rc) {
+					pr_err("regulator_set_mode(%s) failed\n",
+							vregs_qwlan_name[i]);
+					goto vreg_fail;
+				}
+			}
+		}
+		if (on && !wlan_on) {
+			rc = regulator_enable(vregs_qwlan[i]);
+			if (rc < 0) {
+				pr_err("vreg %s enable failed (%d)\n",
+						vregs_qwlan_name[i], rc);
+				goto vreg_fail;
+			}
+		} else if (!on && wlan_on) {
+			rc = regulator_disable(vregs_qwlan[i]);
+			if (rc < 0) {
+				pr_err("vreg %s disable failed (%d)\n",
+						vregs_qwlan_name[i], rc);
+				goto vreg_fail;
+			}
+		}
+	}
+	if (on)
+		wlan_on = true;
+	else
+		wlan_on = false;
+	return 0;
+
+vreg_fail:
+	regulator_put(vregs_qwlan[i]);
+vreg_get_fail:
+	i--;
+	while (i) {
+		ret = !on ? regulator_enable(vregs_qwlan[i]) :
+			regulator_disable(vregs_qwlan[i]);
+		if (ret < 0) {
+			pr_err("vreg %s %s failed (%d) in err path\n",
+					vregs_qwlan_name[i],
+					!on ? "enable" : "disable", ret);
+		}
+		regulator_put(vregs_qwlan[i]);
+		i--;
+	}
+	if (!on)
+		goto fail;
+fail_xo_mode_vote:
+	msm_xo_put(wlan_clock);
+fail_gpio_dir_out:
+	gpio_free(GPIO_WLAN_DEEP_SLEEP_N);
+fail:
+	return rc;
+}
+EXPORT_SYMBOL(vos_chip_power_qrf8615);
+
+/**
+ * qcomwlan_pmic_xo_core_force_enable() - Force XO Core of PMIC to be ALWAYS ON
+ * @on - Force XO Core  ON/OFF (1 or 0)
+ *
+ * The XO_CORE controls the XO feeding the TCXO buffers (A0, A1, etc.). WLAN
+ * wants to keep the XO core on even though our buffer A0 is in pin control
+ * because it can take a long time turn the XO back on and warm up the buffers.
+ * This helps in optimizing power in BMPS (power save) mode of WLAN.
+ * The WLAN driver wrapper function takes care that this API is not called
+ * consecutively.
+ *
+ * This function returns 0 on success or a non-zero value on failure.
+ */
+int qcomwlan_pmic_xo_core_force_enable(int on)
+{
+	static struct msm_xo_voter *wlan_ps;
+	int rc = 0;
+
+	if (wlan_ps == NULL) {
+		wlan_ps = msm_xo_get(MSM_XO_CORE, id);
+		if (IS_ERR(wlan_ps)) {
+			pr_err("Failed to get XO CORE voter (%ld)\n",
+					PTR_ERR(wlan_ps));
+			goto fail;
+		}
+	}
+
+	if (on)
+		rc = msm_xo_mode_vote(wlan_ps, MSM_XO_MODE_ON);
+	else
+		rc = msm_xo_mode_vote(wlan_ps, MSM_XO_MODE_OFF);
+
+	if (rc < 0) {
+		pr_err("XO Core %s failed (%d)\n",
+			on ? "enable" : "disable", rc);
+		goto fail_xo_mode_vote;
+	}
+	return 0;
+fail_xo_mode_vote:
+	msm_xo_put(wlan_ps);
+fail:
+	return rc;
+}
+EXPORT_SYMBOL(qcomwlan_pmic_xo_core_force_enable);
+
+
+/**
+ * qcomwlan_freq_change_1p3v_supply() - function to change the freq for 1.3V RF supply.
+ * @freq - freq of the 1.3V Supply
+ *
+ * This function returns 0 on success or a non-zero value on failure.
+ */
+
+int qcomwlan_freq_change_1p3v_supply(enum rpm_vreg_freq freq)
+{
+	return rpm_vreg_set_frequency(RPM_VREG_ID_PM8058_S2, freq);
+}
+EXPORT_SYMBOL(qcomwlan_freq_change_1p3v_supply);