Merge "msm_vidc: Changes to enable Camcorder" into msm-3.4
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
new file mode 100644
index 0000000..e394b56
--- /dev/null
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -0,0 +1,45 @@
+* Qualcomm WCNSS Platform Driver
+
+WCNSS driver is the platform driver. It is used for performing the cold
+boot-up of the wireless device. It is responsible for adjusting
+the necessary I/O rails and enabling appropriate gpios for wireless
+connectivity subsystem.
+
+Required properties:
+- compatible: "wcnss_wlan"
+- reg: offset and length of the register set for the device. The pair
+ corresponds to PRONTO.
+- interupts: Pronto to Apps interrupts for tx done and rx pending.
+- qcom,pronto-vddmx-supply: regulator to supply pronto pll.
+- qcom,pronto-vddcx-supply: regulator to supply WLAN/BT/FM digital module.
+- qcom,pronto-vddpx-supply: regulator to supply WLAN DAC.
+- qcom,iris-vddxo-supply : regulator to supply RF XO.
+- qcom,iris-vddrfa-supply : regulator to supply RFA digital.
+- qcom,iris-vddpa-supply : regulator to supply RF PA.
+- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
+- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
+- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+
+Example:
+
+ qcom,wcnss-wlan@fb000000 {
+ compatible = "qcom,wcnss_wlan";
+ reg = <0xfb000000 0x280000>;
+ reg-names = "wcnss_mmio";
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8841_s1>;
+ qcom,pronto-vddcx-supply = <&pm8841_s2>;
+ qcom,pronto-vddpx-supply = <&pm8941_s3>;
+ qcom,iris-vddxo-supply = <&pm8941_l6>;
+ qcom,iris-vddrfa-supply = <&pm8941_l11>;
+ qcom,iris-vddpa-supply = <&pm8941_l19>;
+ qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+ gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
+ <&msmgpio 39 0>, <&msmgpio 40 0>;
+ qcom,has_48mhz_xo;
+ qcom,has_pronto_hw;
+ };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index bf73e30..3a2c9f2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -710,6 +710,26 @@
qcom,firmware-name = "wcnss";
};
+ qcom,wcnss-wlan@fb000000 {
+ compatible = "qcom,wcnss_wlan";
+ reg = <0xfb000000 0x280000>;
+ reg-names = "wcnss_mmio";
+ interrupts = <0 145 0 0 146 0>;
+ interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+ qcom,pronto-vddmx-supply = <&pm8841_s1>;
+ qcom,pronto-vddcx-supply = <&pm8841_s2>;
+ qcom,pronto-vddpx-supply = <&pm8941_s3>;
+ qcom,iris-vddxo-supply = <&pm8941_l6>;
+ qcom,iris-vddrfa-supply = <&pm8941_l11>;
+ qcom,iris-vddpa-supply = <&pm8941_l19>;
+ qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+ gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
+ qcom,has_48mhz_xo;
+ qcom,has_pronto_hw;
+ };
+
qcom,ocmem@fdd00000 {
compatible = "qcom,msm-ocmem";
reg = <0xfdd00000 0x2000>,
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 875446e..a40b3cc 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -308,3 +308,7 @@
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_CFG80211=m
+CONFIG_RFKILL=y
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index fd2329f..b385db5 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -60,6 +60,19 @@
},
};
#endif
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_8MA,
@@ -411,6 +424,43 @@
},
},
};
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5wire_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+ },
+ },
+};
static struct msm_gpiomux_config msm_taiko_config[] __initdata = {
{
@@ -435,6 +485,8 @@
msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
#endif
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(msm8974_slimbus_config,
ARRAY_SIZE(msm8974_slimbus_config));
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 7ced65c..0345121 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4966,6 +4966,7 @@
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-lpass"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-mss"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-mba"),
+ CLK_LOOKUP("xo", cxo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil_pronto"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index d3938a0..cc3b956 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -150,28 +150,16 @@
static const char * const _order_8x60_modems[] = {"external_modem", "modem"};
DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems);
-/* MSM 8960 restart ordering info */
-static const char * const order_8960[] = {"modem", "lpass"};
/*SGLTE restart ordering info*/
static const char * const order_8960_sglte[] = {"external_modem",
"modem"};
-static struct subsys_soc_restart_order restart_orders_8960_one = {
- .subsystem_list = order_8960,
- .count = ARRAY_SIZE(order_8960),
- .subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL}
- };
-
static struct subsys_soc_restart_order restart_orders_8960_fusion_sglte = {
.subsystem_list = order_8960_sglte,
.count = ARRAY_SIZE(order_8960_sglte),
.subsys_ptrs = {[ARRAY_SIZE(order_8960_sglte)] = NULL}
};
-static struct subsys_soc_restart_order *restart_orders_8960[] = {
- &restart_orders_8960_one,
- };
-
static struct subsys_soc_restart_order *restart_orders_8960_sglte[] = {
&restart_orders_8960_fusion_sglte,
};
@@ -205,9 +193,13 @@
return ret;
switch (restart_level) {
- case RESET_SOC:
- case RESET_SUBSYS_COUPLED:
case RESET_SUBSYS_INDEPENDENT:
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+ pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
+ restart_level = RESET_SUBSYS_COUPLED;
+ }
+ case RESET_SUBSYS_COUPLED:
+ case RESET_SOC:
pr_info("Phase %d behavior activated.\n", restart_level);
break;
default:
@@ -754,21 +746,14 @@
n_restart_orders = ARRAY_SIZE(orders_8x60_all);
}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
- cpu_is_msm8960ab()) {
- if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
- restart_orders = restart_orders_8960_sglte;
- n_restart_orders =
- ARRAY_SIZE(restart_orders_8960_sglte);
- } else {
- restart_orders = restart_orders_8960;
- n_restart_orders = ARRAY_SIZE(restart_orders_8960);
- }
- for (i = 0; i < n_restart_orders; i++) {
- mutex_init(&restart_orders[i]->powerup_lock);
- mutex_init(&restart_orders[i]->shutdown_lock);
- }
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+ restart_orders = restart_orders_8960_sglte;
+ n_restart_orders = ARRAY_SIZE(restart_orders_8960_sglte);
+ }
+
+ for (i = 0; i < n_restart_orders; i++) {
+ mutex_init(&restart_orders[i]->powerup_lock);
+ mutex_init(&restart_orders[i]->shutdown_lock);
}
if (restart_orders == NULL || n_restart_orders < 1) {
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
index b0782a3..6ac4a5e 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -477,9 +477,11 @@
buf_p->y_buffer_addr = msm_jpeg_platform_v2p(buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
- &buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset;
+ &buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset
+ + buf_cmd.y_off;
buf_p->y_len = buf_cmd.y_len;
- buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
+ + buf_cmd.cbcr_off;
buf_p->cbcr_len = buf_cmd.cbcr_len;
buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%x, fd =%d\n",
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 914f4fb..9b8ab39 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -295,7 +295,7 @@
config WCNSS_CORE
tristate "Qualcomm WCNSS CORE driver"
- depends on ARCH_MSM8960
+ depends on (ARCH_MSM8960 || ARCH_MSM8974)
select WIRELESS_EXT
select WEXT_PRIV
select WEXT_CORE
@@ -303,6 +303,12 @@
---help---
Core driver for the Qualcomm WCNSS triple play connectivity subsystem
+config WCNSS_CORE_PRONTO
+ tristate "Qualcomm WCNSS Pronto Support"
+ depends on WCNSS_CORE
+ ---help---
+ Pronto Support for the Qualcomm WCNSS triple play connectivity subsystem
+
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
diff --git a/drivers/net/wireless/wcnss/Makefile b/drivers/net/wireless/wcnss/Makefile
index c077848..11fa673 100644
--- a/drivers/net/wireless/wcnss/Makefile
+++ b/drivers/net/wireless/wcnss/Makefile
@@ -1,6 +1,6 @@
# Makefile for WCNSS triple-play driver
-wcnsscore-objs += wcnss_wlan.o wcnss_riva.o qcomwlan_secif.o
+wcnsscore-objs += wcnss_wlan.o qcomwlan_secif.o wcnss_vreg.o
obj-$(CONFIG_WCNSS_CORE) += wcnsscore.o
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
deleted file mode 100644
index 2d9ad82..0000000
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/* Copyright (c) 2011-2012, 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/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/pm8xxx/gpio.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/semaphore.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <mach/msm_xo.h>
-#include <mach/msm_iomap.h>
-
-
-static void __iomem *msm_riva_base;
-static struct msm_xo_voter *wlan_clock;
-static const char *id = "WLAN";
-static LIST_HEAD(power_on_lock_list);
-static DEFINE_MUTEX(list_lock);
-static DEFINE_SEMAPHORE(riva_power_on_lock);
-
-#define MSM_RIVA_PHYS 0x03204000
-#define RIVA_PMU_CFG (msm_riva_base + 0x28)
-#define RIVA_PMU_CFG_IRIS_XO_CFG BIT(3)
-#define RIVA_PMU_CFG_IRIS_XO_EN BIT(4)
-#define RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5)
-#define RIVA_PMU_CFG_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
-
-#define RIVA_PMU_CFG_IRIS_XO_MODE 0x6
-#define RIVA_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
-
-#define VREG_NULL_CONFIG 0x0000
-#define VREG_GET_REGULATOR_MASK 0x0001
-#define VREG_SET_VOLTAGE_MASK 0x0002
-#define VREG_OPTIMUM_MODE_MASK 0x0004
-#define VREG_ENABLE_MASK 0x0008
-
-struct vregs_info {
- const char * const name;
- int state;
- const int nominal_min;
- const int low_power_min;
- const int max_voltage;
- const int uA_load;
- struct regulator *regulator;
-};
-
-static struct vregs_info iris_vregs[] = {
- {"iris_vddxo", VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000, NULL},
- {"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
- {"iris_vddpa", VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
- {"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000, NULL},
-};
-
-static struct vregs_info riva_vregs[] = {
- {"riva_vddmx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
- {"riva_vddcx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
- {"riva_vddpx", VREG_NULL_CONFIG, 1800000, 0, 1800000, 0, NULL},
-};
-
-struct host_driver {
- char name[20];
- struct list_head list;
-};
-
-
-static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
-{
- u32 reg = 0;
- int rc = 0;
- struct clk *cxo = clk_get(dev, "cxo");
- if (IS_ERR(cxo)) {
- pr_err("Couldn't get cxo clock\n");
- return PTR_ERR(cxo);
- }
-
- if (on) {
- msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
- if (!msm_riva_base) {
- pr_err("ioremap MSM_RIVA_PHYS failed\n");
- goto fail;
- }
-
- /* Enable IRIS XO */
- rc = clk_prepare_enable(cxo);
- if (rc) {
- pr_err("cxo enable failed\n");
- goto fail;
- }
- writel_relaxed(0, RIVA_PMU_CFG);
- reg = readl_relaxed(RIVA_PMU_CFG);
- reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
- RIVA_PMU_CFG_IRIS_XO_EN;
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
- reg &= ~(RIVA_PMU_CFG_IRIS_XO_MODE);
-
- if (use_48mhz_xo)
- reg |= RIVA_PMU_CFG_IRIS_XO_MODE_48;
-
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Start IRIS XO configuration */
- reg |= RIVA_PMU_CFG_IRIS_XO_CFG;
- writel_relaxed(reg, RIVA_PMU_CFG);
-
- /* Wait for XO configuration to finish */
- while (readl_relaxed(RIVA_PMU_CFG) &
- RIVA_PMU_CFG_IRIS_XO_CFG_STS)
- cpu_relax();
-
- /* Stop IRIS XO configuration */
- reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
- RIVA_PMU_CFG_IRIS_XO_CFG);
- writel_relaxed(reg, RIVA_PMU_CFG);
- clk_disable_unprepare(cxo);
-
- if (!use_48mhz_xo) {
- wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
- if (IS_ERR(wlan_clock)) {
- rc = PTR_ERR(wlan_clock);
- pr_err("Failed to get MSM_XO_TCXO_A2 voter"
- " (%d)\n", rc);
- goto fail;
- }
-
- rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
- if (rc < 0) {
- pr_err("Configuring MSM_XO_MODE_ON failed"
- " (%d)\n", rc);
- goto msm_xo_vote_fail;
- }
- }
- } else {
- if (wlan_clock != NULL && !use_48mhz_xo) {
- rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
- if (rc < 0)
- pr_err("Configuring MSM_XO_MODE_OFF failed"
- " (%d)\n", rc);
- }
- }
-
- /* Add some delay for XO to settle */
- msleep(20);
-
- clk_put(cxo);
- return rc;
-
-msm_xo_vote_fail:
- msm_xo_put(wlan_clock);
-
-fail:
- clk_put(cxo);
- return rc;
-}
-
-/* Helper routine to turn off all WCNSS vregs e.g. IRIS, Riva */
-static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
-{
- int i, rc = 0;
-
- /* Regulators need to be turned off in the reverse order */
- for (i = (size-1); i >= 0; i--) {
- if (regulators[i].state == VREG_NULL_CONFIG)
- continue;
-
- /* Remove PWM mode */
- if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
- rc = regulator_set_optimum_mode(
- regulators[i].regulator, 0);
- if (rc < 0)
- pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
- regulators[i].name, rc);
- }
-
- /* Set voltage to lowest level */
- if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
- rc = regulator_set_voltage(regulators[i].regulator,
- regulators[i].low_power_min,
- regulators[i].max_voltage);
- if (rc)
- pr_err("regulator_set_voltage(%s) failed (%d)\n",
- regulators[i].name, rc);
- }
-
- /* Disable regulator */
- if (regulators[i].state & VREG_ENABLE_MASK) {
- rc = regulator_disable(regulators[i].regulator);
- if (rc < 0)
- pr_err("vreg %s disable failed (%d)\n",
- regulators[i].name, rc);
- }
-
- /* Free the regulator source */
- if (regulators[i].state & VREG_GET_REGULATOR_MASK)
- regulator_put(regulators[i].regulator);
-
- regulators[i].state = VREG_NULL_CONFIG;
- }
-}
-
-/* Common helper routine to turn on all WCNSS vregs e.g. IRIS, Riva */
-static int wcnss_vregs_on(struct device *dev,
- struct vregs_info regulators[], uint size)
-{
- int i, rc = 0, reg_cnt;
-
- for (i = 0; i < size; i++) {
- /* Get regulator source */
- regulators[i].regulator =
- regulator_get(dev, regulators[i].name);
- if (IS_ERR(regulators[i].regulator)) {
- rc = PTR_ERR(regulators[i].regulator);
- pr_err("regulator get of %s failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_GET_REGULATOR_MASK;
- reg_cnt = regulator_count_voltages(regulators[i].regulator);
- /* Set voltage to nominal. Exclude swtiches e.g. LVS */
- if ((regulators[i].nominal_min || regulators[i].max_voltage)
- && (reg_cnt > 0)) {
- rc = regulator_set_voltage(regulators[i].regulator,
- regulators[i].nominal_min,
- regulators[i].max_voltage);
- if (rc) {
- pr_err("regulator_set_voltage(%s) failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_SET_VOLTAGE_MASK;
- }
-
- /* Vote for PWM/PFM mode if needed */
- if (regulators[i].uA_load && (reg_cnt > 0)) {
- rc = regulator_set_optimum_mode(regulators[i].regulator,
- regulators[i].uA_load);
- if (rc < 0) {
- pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
- }
-
- /* Enable the regulator */
- rc = regulator_enable(regulators[i].regulator);
- if (rc) {
- pr_err("vreg %s enable failed (%d)\n",
- regulators[i].name, rc);
- goto fail;
- }
- regulators[i].state |= VREG_ENABLE_MASK;
- }
-
- return rc;
-
-fail:
- wcnss_vregs_off(regulators, size);
- return rc;
-
-}
-
-static void wcnss_iris_vregs_off(void)
-{
- wcnss_vregs_off(iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static int wcnss_iris_vregs_on(struct device *dev)
-{
- return wcnss_vregs_on(dev, iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static void wcnss_riva_vregs_off(void)
-{
- wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-static int wcnss_riva_vregs_on(struct device *dev)
-{
- return wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-int wcnss_wlan_power(struct device *dev,
- struct wcnss_wlan_config *cfg,
- enum wcnss_opcode on)
-{
- int rc = 0;
-
- if (on) {
- down(&riva_power_on_lock);
- /* RIVA regulator settings */
- rc = wcnss_riva_vregs_on(dev);
- if (rc)
- goto fail_riva_on;
-
- /* IRIS regulator settings */
- rc = wcnss_iris_vregs_on(dev);
- if (rc)
- goto fail_iris_on;
-
- /* Configure IRIS XO */
- rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
- WCNSS_WLAN_SWITCH_ON);
- if (rc)
- goto fail_iris_xo;
- up(&riva_power_on_lock);
-
- } else {
- configure_iris_xo(dev, cfg->use_48mhz_xo,
- WCNSS_WLAN_SWITCH_OFF);
- wcnss_iris_vregs_off();
- wcnss_riva_vregs_off();
- }
-
- return rc;
-
-fail_iris_xo:
- wcnss_iris_vregs_off();
-
-fail_iris_on:
- wcnss_riva_vregs_off();
-
-fail_riva_on:
- up(&riva_power_on_lock);
- return rc;
-}
-EXPORT_SYMBOL(wcnss_wlan_power);
-
-/*
- * During SSR Riva should not be 'powered on' until all the host drivers
- * finish their shutdown routines. Host drivers use below APIs to
- * synchronize power-on. Riva will not be 'powered on' until all the
- * requests(to lock power-on) are freed.
- */
-int req_riva_power_on_lock(char *driver_name)
-{
- struct host_driver *node;
-
- if (!driver_name)
- goto err;
-
- node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
- if (!node)
- goto err;
- strncpy(node->name, driver_name, sizeof(node->name));
-
- mutex_lock(&list_lock);
- /* Lock when the first request is added */
- if (list_empty(&power_on_lock_list))
- down(&riva_power_on_lock);
- list_add(&node->list, &power_on_lock_list);
- mutex_unlock(&list_lock);
-
- return 0;
-
-err:
- return -EINVAL;
-}
-EXPORT_SYMBOL(req_riva_power_on_lock);
-
-int free_riva_power_on_lock(char *driver_name)
-{
- int ret = -1;
- struct host_driver *node;
-
- mutex_lock(&list_lock);
- list_for_each_entry(node, &power_on_lock_list, list) {
- if (!strncmp(node->name, driver_name, sizeof(node->name))) {
- list_del(&node->list);
- kfree(node);
- ret = 0;
- break;
- }
- }
- /* unlock when the last host driver frees the lock */
- if (list_empty(&power_on_lock_list))
- up(&riva_power_on_lock);
- mutex_unlock(&list_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(free_riva_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
new file mode 100644
index 0000000..01b27dd
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2012, The Linux Foundation. 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/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/wcnss_wlan.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <mach/msm_xo.h>
+#include <mach/msm_iomap.h>
+
+
+static void __iomem *msm_wcnss_base;
+static struct msm_xo_voter *wlan_clock;
+static const char *id = "WLAN";
+static LIST_HEAD(power_on_lock_list);
+static DEFINE_MUTEX(list_lock);
+static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+
+#define MSM_RIVA_PHYS 0x03204000
+#define MSM_PRONTO_PHYS 0xfb21b000
+
+#define RIVA_PMU_OFFSET 0x28
+#define PRONTO_PMU_OFFSET 0x1004
+
+#define WCNSS_PMU_CFG_IRIS_XO_CFG BIT(3)
+#define WCNSS_PMU_CFG_IRIS_XO_EN BIT(4)
+#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5)
+#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_CFG_IRIS_XO_MODE 0x6
+#define WCNSS_PMU_CFG_IRIS_XO_MODE_48 (3 << 1)
+
+#define VREG_NULL_CONFIG 0x0000
+#define VREG_GET_REGULATOR_MASK 0x0001
+#define VREG_SET_VOLTAGE_MASK 0x0002
+#define VREG_OPTIMUM_MODE_MASK 0x0004
+#define VREG_ENABLE_MASK 0x0008
+
+struct vregs_info {
+ const char * const name;
+ int state;
+ const int nominal_min;
+ const int low_power_min;
+ const int max_voltage;
+ const int uA_load;
+ struct regulator *regulator;
+};
+
+/* IRIS regulators for Riva hardware */
+static struct vregs_info iris_vregs_riva[] = {
+ {"iris_vddxo", VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000, NULL},
+ {"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
+ {"iris_vddpa", VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
+ {"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000, NULL},
+};
+
+/* WCNSS regulators for Riva hardware */
+static struct vregs_info riva_vregs[] = {
+ /* Riva */
+ {"riva_vddmx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
+ {"riva_vddcx", VREG_NULL_CONFIG, 1050000, 0, 1150000, 0, NULL},
+ {"riva_vddpx", VREG_NULL_CONFIG, 1800000, 0, 1800000, 0, NULL},
+};
+
+/* IRIS regulators for Pronto hardware */
+static struct vregs_info iris_vregs_pronto[] = {
+ {"qcom,iris-vddxo", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 10000, NULL},
+ {"qcom,iris-vddrfa", VREG_NULL_CONFIG, 1300000, 0,
+ 1300000, 100000, NULL},
+ {"qcom,iris-vddpa", VREG_NULL_CONFIG, 2900000, 0,
+ 3000000, 515000, NULL},
+ {"qcom,iris-vdddig", VREG_NULL_CONFIG, 1225000, 0,
+ 1225000, 10000, NULL},
+};
+
+/* WCNSS regulators for Pronto hardware */
+static struct vregs_info pronto_vregs[] = {
+ {"qcom,pronto-vddmx", VREG_NULL_CONFIG, 950000, 0,
+ 1150000, 0, NULL},
+ {"qcom,pronto-vddcx", VREG_NULL_CONFIG, 900000, 0,
+ 1150000, 0, NULL},
+ {"qcom,pronto-vddpx", VREG_NULL_CONFIG, 1800000, 0,
+ 1800000, 0, NULL},
+};
+
+
+struct host_driver {
+ char name[20];
+ struct list_head list;
+};
+
+
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
+{
+ u32 reg = 0;
+ int rc = 0;
+ int size = 0;
+ int pmu_offset = 0;
+ unsigned long wcnss_phys_addr;
+ void __iomem *pmu_conf_reg;
+ struct clk *clk;
+
+ if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
+ wcnss_phys_addr = MSM_PRONTO_PHYS;
+ pmu_offset = PRONTO_PMU_OFFSET;
+ size = 0x3000;
+
+ clk = clk_get(dev, "xo");
+ if (IS_ERR(clk)) {
+ pr_err("Couldn't get xo clock\n");
+ return PTR_ERR(clk);
+ }
+ } else {
+ wcnss_phys_addr = MSM_RIVA_PHYS;
+ pmu_offset = RIVA_PMU_OFFSET;
+ size = SZ_256;
+
+ clk = clk_get(dev, "cxo");
+ if (IS_ERR(clk)) {
+ pr_err("Couldn't get cxo clock\n");
+ return PTR_ERR(clk);
+ }
+ }
+
+ if (on) {
+ msm_wcnss_base = ioremap(wcnss_phys_addr, size);
+ if (!msm_wcnss_base) {
+ pr_err("ioremap wcnss physical failed\n");
+ goto fail;
+ }
+ pmu_conf_reg = msm_wcnss_base + pmu_offset;
+
+ /* Enable IRIS XO */
+ rc = clk_prepare_enable(clk);
+ if (rc) {
+ pr_err("clk enable failed\n");
+ goto fail;
+ }
+ writel_relaxed(0, pmu_conf_reg);
+ reg = readl_relaxed(pmu_conf_reg);
+ reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+ WCNSS_PMU_CFG_IRIS_XO_EN;
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
+ reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
+
+ if (use_48mhz_xo)
+ reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
+
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Start IRIS XO configuration */
+ reg |= WCNSS_PMU_CFG_IRIS_XO_CFG;
+ writel_relaxed(reg, pmu_conf_reg);
+
+ /* Wait for XO configuration to finish */
+ while (readl_relaxed(pmu_conf_reg) &
+ WCNSS_PMU_CFG_IRIS_XO_CFG_STS)
+ cpu_relax();
+
+ /* Stop IRIS XO configuration */
+ reg &= ~(WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+ WCNSS_PMU_CFG_IRIS_XO_CFG);
+ writel_relaxed(reg, pmu_conf_reg);
+ clk_disable_unprepare(clk);
+
+ if (!use_48mhz_xo) {
+ wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
+ if (IS_ERR(wlan_clock)) {
+ rc = PTR_ERR(wlan_clock);
+ pr_err("Failed to get MSM_XO_TCXO_A2 voter (%d)\n",
+ rc);
+ goto fail;
+ }
+
+ rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
+ if (rc < 0) {
+ pr_err("Configuring MSM_XO_MODE_ON failed (%d)\n",
+ rc);
+ goto msm_xo_vote_fail;
+ }
+ }
+ } else {
+ if (wlan_clock != NULL && !use_48mhz_xo) {
+ rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
+ if (rc < 0)
+ pr_err("Configuring MSM_XO_MODE_OFF failed (%d)\n",
+ rc);
+ }
+ }
+
+ /* Add some delay for XO to settle */
+ msleep(20);
+
+ clk_put(clk);
+ return rc;
+
+msm_xo_vote_fail:
+ msm_xo_put(wlan_clock);
+
+fail:
+ clk_put(clk);
+ return rc;
+}
+
+/* Helper routine to turn off all WCNSS & IRIS vregs */
+static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
+{
+ int i, rc = 0;
+
+ /* Regulators need to be turned off in the reverse order */
+ for (i = (size-1); i >= 0; i--) {
+ if (regulators[i].state == VREG_NULL_CONFIG)
+ continue;
+
+ /* Remove PWM mode */
+ if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
+ rc = regulator_set_optimum_mode(
+ regulators[i].regulator, 0);
+ if (rc < 0)
+ pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ }
+
+ /* Set voltage to lowest level */
+ if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
+ rc = regulator_set_voltage(regulators[i].regulator,
+ regulators[i].low_power_min,
+ regulators[i].max_voltage);
+ if (rc)
+ pr_err("regulator_set_voltage(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ }
+
+ /* Disable regulator */
+ if (regulators[i].state & VREG_ENABLE_MASK) {
+ rc = regulator_disable(regulators[i].regulator);
+ if (rc < 0)
+ pr_err("vreg %s disable failed (%d)\n",
+ regulators[i].name, rc);
+ }
+
+ /* Free the regulator source */
+ if (regulators[i].state & VREG_GET_REGULATOR_MASK)
+ regulator_put(regulators[i].regulator);
+
+ regulators[i].state = VREG_NULL_CONFIG;
+ }
+}
+
+/* Common helper routine to turn on all WCNSS & IRIS vregs */
+static int wcnss_vregs_on(struct device *dev,
+ struct vregs_info regulators[], uint size)
+{
+ int i, rc = 0, reg_cnt;
+
+ for (i = 0; i < size; i++) {
+ /* Get regulator source */
+ regulators[i].regulator =
+ regulator_get(dev, regulators[i].name);
+ if (IS_ERR(regulators[i].regulator)) {
+ rc = PTR_ERR(regulators[i].regulator);
+ pr_err("regulator get of %s failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_GET_REGULATOR_MASK;
+ reg_cnt = regulator_count_voltages(regulators[i].regulator);
+ /* Set voltage to nominal. Exclude swtiches e.g. LVS */
+ if ((regulators[i].nominal_min || regulators[i].max_voltage)
+ && (reg_cnt > 0)) {
+ rc = regulator_set_voltage(regulators[i].regulator,
+ regulators[i].nominal_min,
+ regulators[i].max_voltage);
+ if (rc) {
+ pr_err("regulator_set_voltage(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_SET_VOLTAGE_MASK;
+ }
+
+ /* Vote for PWM/PFM mode if needed */
+ if (regulators[i].uA_load && (reg_cnt > 0)) {
+ rc = regulator_set_optimum_mode(regulators[i].regulator,
+ regulators[i].uA_load);
+ if (rc < 0) {
+ pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
+ }
+
+ /* Enable the regulator */
+ rc = regulator_enable(regulators[i].regulator);
+ if (rc) {
+ pr_err("vreg %s enable failed (%d)\n",
+ regulators[i].name, rc);
+ goto fail;
+ }
+ regulators[i].state |= VREG_ENABLE_MASK;
+ }
+
+ return rc;
+
+fail:
+ wcnss_vregs_off(regulators, size);
+ return rc;
+
+}
+
+static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type)
+{
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ wcnss_vregs_off(iris_vregs_riva, ARRAY_SIZE(iris_vregs_riva));
+ break;
+ case WCNSS_PRONTO_HW:
+ wcnss_vregs_off(iris_vregs_pronto,
+ ARRAY_SIZE(iris_vregs_pronto));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+
+ }
+}
+
+static int wcnss_iris_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+ int ret = -1;
+
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ ret = wcnss_vregs_on(dev, iris_vregs_riva,
+ ARRAY_SIZE(iris_vregs_riva));
+ break;
+ case WCNSS_PRONTO_HW:
+ ret = wcnss_vregs_on(dev, iris_vregs_pronto,
+ ARRAY_SIZE(iris_vregs_pronto));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ }
+ return ret;
+}
+
+static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type)
+{
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
+ break;
+ case WCNSS_PRONTO_HW:
+ wcnss_vregs_off(pronto_vregs, ARRAY_SIZE(pronto_vregs));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ }
+
+}
+
+static int wcnss_core_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+ int ret = -1;
+
+ switch (hw_type) {
+ case WCNSS_RIVA_HW:
+ ret = wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
+ break;
+ case WCNSS_PRONTO_HW:
+ ret = wcnss_vregs_on(dev, pronto_vregs,
+ ARRAY_SIZE(pronto_vregs));
+ break;
+ default:
+ pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ }
+
+ return ret;
+
+}
+
+int wcnss_wlan_power(struct device *dev,
+ struct wcnss_wlan_config *cfg,
+ enum wcnss_opcode on)
+{
+ int rc = 0;
+ enum wcnss_hw_type hw_type = wcnss_hardware_type();
+
+ if (on) {
+ down(&wcnss_power_on_lock);
+ /* RIVA regulator settings */
+ rc = wcnss_core_vregs_on(dev, hw_type);
+ if (rc)
+ goto fail_wcnss_on;
+
+ /* IRIS regulator settings */
+ rc = wcnss_iris_vregs_on(dev, hw_type);
+ if (rc)
+ goto fail_iris_on;
+
+ /* Configure IRIS XO */
+ rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+ WCNSS_WLAN_SWITCH_ON);
+ if (rc)
+ goto fail_iris_xo;
+ up(&wcnss_power_on_lock);
+
+ } else {
+ configure_iris_xo(dev, cfg->use_48mhz_xo,
+ WCNSS_WLAN_SWITCH_OFF);
+ wcnss_iris_vregs_off(hw_type);
+ wcnss_core_vregs_off(hw_type);
+ }
+
+ return rc;
+
+fail_iris_xo:
+ wcnss_iris_vregs_off(hw_type);
+
+fail_iris_on:
+ wcnss_core_vregs_off(hw_type);
+
+fail_wcnss_on:
+ up(&wcnss_power_on_lock);
+ return rc;
+}
+EXPORT_SYMBOL(wcnss_wlan_power);
+
+/*
+ * During SSR WCNSS should not be 'powered on' until all the host drivers
+ * finish their shutdown routines. Host drivers use below APIs to
+ * synchronize power-on. WCNSS will not be 'powered on' until all the
+ * requests(to lock power-on) are freed.
+ */
+int wcnss_req_power_on_lock(char *driver_name)
+{
+ struct host_driver *node;
+
+ if (!driver_name)
+ goto err;
+
+ node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
+ if (!node)
+ goto err;
+ strlcpy(node->name, driver_name, sizeof(node->name));
+
+ mutex_lock(&list_lock);
+ /* Lock when the first request is added */
+ if (list_empty(&power_on_lock_list))
+ down(&wcnss_power_on_lock);
+ list_add(&node->list, &power_on_lock_list);
+ mutex_unlock(&list_lock);
+
+ return 0;
+
+err:
+ return -EINVAL;
+}
+EXPORT_SYMBOL(wcnss_req_power_on_lock);
+
+int wcnss_free_power_on_lock(char *driver_name)
+{
+ int ret = -1;
+ struct host_driver *node;
+
+ mutex_lock(&list_lock);
+ list_for_each_entry(node, &power_on_lock_list, list) {
+ if (!strncmp(node->name, driver_name, sizeof(node->name))) {
+ list_del(&node->list);
+ kfree(node);
+ ret = 0;
+ break;
+ }
+ }
+ /* unlock when the last host driver frees the lock */
+ if (list_empty(&power_on_lock_list))
+ up(&wcnss_power_on_lock);
+ mutex_unlock(&list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(wcnss_free_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 633809a..e83b195 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -23,6 +23,8 @@
#include <linux/gpio.h>
#include <linux/wakelock.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <mach/peripheral-loader.h>
#include <mach/msm_smd.h>
@@ -76,6 +78,7 @@
unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned int serial_number;
int thermal_mitigation;
+ enum wcnss_hw_type wcnss_hw_type;
void (*tm_notify)(struct device *, int);
struct wcnss_wlan_config wlan_config;
struct delayed_work wcnss_work;
@@ -225,11 +228,42 @@
static void wcnss_post_bootup(struct work_struct *work)
{
- pr_info("%s: Cancel APPS vote for Iris & Riva\n", __func__);
+ pr_info("%s: Cancel APPS vote for Iris & WCNSS\n", __func__);
- /* Since Riva is up, cancel any APPS vote for Iris & Riva VREGs */
+ /* Since WCNSS is up, cancel any APPS vote for Iris & WCNSS VREGs */
wcnss_wlan_power(&penv->pdev->dev, &penv->wlan_config,
WCNSS_WLAN_SWITCH_OFF);
+
+}
+
+static int
+wcnss_pronto_gpios_config(struct device *dev, bool enable)
+{
+ int rc = 0;
+ int i, j;
+ int WCNSS_WLAN_NUM_GPIOS = 5;
+
+ for (i = 0; i < WCNSS_WLAN_NUM_GPIOS; i++) {
+ int gpio = of_get_gpio(dev->of_node, i);
+ if (enable) {
+ rc = gpio_request(gpio, "wcnss_wlan");
+ if (rc) {
+ pr_err("WCNSS gpio_request %d err %d\n",
+ gpio, rc);
+ goto fail;
+ }
+ } else
+ gpio_free(gpio);
+ }
+
+ return rc;
+
+fail:
+ for (j = WCNSS_WLAN_NUM_GPIOS-1; j >= 0; j--) {
+ int gpio = of_get_gpio(dev->of_node, i);
+ gpio_free(gpio);
+ }
+ return rc;
}
static int
@@ -469,6 +503,15 @@
}
EXPORT_SYMBOL(wcnss_allow_suspend);
+int wcnss_hardware_type(void)
+{
+ if (penv)
+ return penv->wcnss_hw_type;
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_hardware_type);
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -551,6 +594,8 @@
{
int ret;
struct qcom_wcnss_opts *pdata;
+ int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has_pronto_hw");
/* make sure we are only triggered once */
if (penv->triggered)
@@ -559,25 +604,36 @@
/* initialize the WCNSS device configuration */
pdata = pdev->dev.platform_data;
- if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo)
- has_48mhz_xo = pdata->has_48mhz_xo;
+ if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
+ if (has_pronto_hw) {
+ has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
+ "qcom,has_48mhz_xo");
+ penv->wcnss_hw_type = WCNSS_PRONTO_HW;
+ } else {
+ penv->wcnss_hw_type = WCNSS_RIVA_HW;
+ has_48mhz_xo = pdata->has_48mhz_xo;
+ }
+ }
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
penv->thermal_mitigation = 0;
strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
- 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 (!has_pronto_hw) {
+ 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;
+ }
+ ret = wcnss_gpios_config(penv->gpios_5wire, true);
+ } else
+ ret = wcnss_pronto_gpios_config(&pdev->dev, true);
+
if (ret) {
dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
goto fail_gpio_res;
@@ -627,7 +683,10 @@
wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
WCNSS_WLAN_SWITCH_OFF);
fail_power:
- wcnss_gpios_config(penv->gpios_5wire, false);
+ if (has_pronto_hw)
+ ret = wcnss_pronto_gpios_config(&pdev->dev, false);
+ else
+ wcnss_gpios_config(penv->gpios_5wire, false);
fail_gpio_res:
kfree(penv);
penv = NULL;
@@ -724,11 +783,21 @@
.resume = wcnss_wlan_resume,
};
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+static struct of_device_id msm_wcnss_pronto_match[] = {
+ {.compatible = "qcom,wcnss_wlan"},
+ {}
+};
+#endif
+
static struct platform_driver wcnss_wlan_driver = {
.driver = {
.name = DEVICE,
.owner = THIS_MODULE,
.pm = &wcnss_wlan_pm_ops,
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+ .of_match_table = msm_wcnss_pronto_match,
+#endif
},
.probe = wcnss_wlan_probe,
.remove = __devexit_p(wcnss_wlan_remove),
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 295be8f..cf7b555 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -21,6 +21,11 @@
WCNSS_WLAN_SWITCH_ON,
};
+enum wcnss_hw_type {
+ WCNSS_RIVA_HW = 0,
+ WCNSS_PRONTO_HW,
+};
+
struct wcnss_wlan_config {
int use_48mhz_xo;
};
@@ -44,13 +49,17 @@
int wcnss_wlan_power(struct device *dev,
struct wcnss_wlan_config *cfg,
enum wcnss_opcode opcode);
-int req_riva_power_on_lock(char *driver_name);
-int free_riva_power_on_lock(char *driver_name);
+int wcnss_req_power_on_lock(char *driver_name);
+int wcnss_free_power_on_lock(char *driver_name);
unsigned int wcnss_get_serial_number(void);
void wcnss_flush_delayed_boot_votes(void);
void wcnss_allow_suspend(void);
void wcnss_prevent_suspend(void);
+int wcnss_hardware_type(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
+/* WLAN driver uses these names */
+#define req_riva_power_on_lock(name) wcnss_req_power_on_lock(name)
+#define free_riva_power_on_lock(name) wcnss_free_power_on_lock(name)
#endif /* _WCNSS_WLAN_H_ */