From 06782fb5db473009d1da0ccee04a10eac93905f1 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Mon, 31 Jul 2017 15:38:14 +0530 Subject: [PATCH 1/3] wcnss: Add support to enable and disable wcnss snoc clock It is a hardware requirement to increase snoc clock frequency in HID sniff mode due to low wlan throughput. To provide this, add support to enable and disable snoc clock. Update the voltage regulator configuration API as per upstream kernel. CRs-Fixed: 1101377 Change-Id: I1130353bf861ca31792c40ef51243497788ed56d Signed-off-by: Sarada Prasanna Garnayak --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 14 ++++-- drivers/net/wireless/wcnss/wcnss_vreg.c | 20 ++++---- drivers/net/wireless/wcnss/wcnss_wlan.c | 49 +++++++++++++++++++ include/linux/wcnss_wlan.h | 4 +- 4 files changed, 73 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 061c1d16ad24..63ecac4c68e7 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -29,7 +29,7 @@ Required properties: - qcom,wcnss-vadc: VADC handle for battery voltage notification APIs. - pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt - pinctrl-names : Names corresponding to the numbered pinctrl states -- clocks: from common clock binding: handle to xo and rf_clk clocks. +- clocks: from common clock binding: handle to xo, rf_clk and wcnss snoc clocks. - clock-names: Names of all the clocks that are accessed by the subsystem - qcom,vdd-voltage-level: This property represents (nominal, min, max) voltage for iris and pronto regulators in milli-volts. @@ -39,6 +39,9 @@ iris and pronto regulators in micro-amps. Optional properties: - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect should be performed during boot up. +- qcom,snoc-wcnss-clock-freq: indicates the wcnss snoc clock frequency in Hz. +If wcnss_snoc clock is specified in the list of clocks, this property needs +to be set to make it functional. - qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value, using a smaller count for this buffer will reduce the memory usage. - qcom,is-pronto-v3: boolean flag to determine the pronto hardware version @@ -94,7 +97,12 @@ Example: clocks = <&clock_rpm clk_xo_wlan_clk>, <&clock_rpm clk_rf_clk2>, <&clock_debug clk_gcc_debug_mux>, - <&clock_gcc clk_wcnss_m_clk>; - clock-names = "xo", "rf_clk", "measure", "wcnss_debug"; + <&clock_gcc clk_wcnss_m_clk>, + <&clock_gcc clk_snoc_wcnss_a_clk>; + + clock-names = "xo", "rf_clk", "measure", "wcnss_debug", + "snoc_wcnss"; + + qcom,snoc-wcnss-clock-freq = <200000000>; qcom,wcnss-pm = <11 21 1200 1 1 6>; }; diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index 82b90ad00f8b..4f4ee15b133f 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017 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 @@ -419,11 +419,11 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size, /* 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); + rc = regulator_set_load(regulators[i].regulator, 0); + if (rc < 0) { + pr_err("regulator set load(%s) failed (%d)\n", + regulators[i].name, rc); + } } /* Set voltage to lowest level */ @@ -518,11 +518,11 @@ static int wcnss_vregs_on(struct device *dev, /* Vote for PWM/PFM mode if needed */ if (voltage_level[i].uA_load && (reg_cnt > 0)) { - rc = regulator_set_optimum_mode(regulators[i].regulator, - voltage_level[i].uA_load); + rc = regulator_set_load(regulators[i].regulator, + voltage_level[i].uA_load); if (rc < 0) { - pr_err("regulator_set_optimum_mode(%s) failed (%d)\n", - regulators[i].name, rc); + pr_err("regulator set load(%s) failed (%d)\n", + regulators[i].name, rc); goto fail; } regulators[i].state |= VREG_OPTIMUM_MODE_MASK; diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 9347882fba92..6ff812a35557 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -423,6 +423,8 @@ static struct { int pc_disabled; struct delayed_work wcnss_pm_qos_del_req; struct mutex pm_qos_mutex; + struct clk *snoc_wcnss; + unsigned int snoc_wcnss_clock_freq; } *penv = NULL; static ssize_t wcnss_wlan_macaddr_store(struct device *dev, @@ -3129,6 +3131,21 @@ wcnss_trigger_config(struct platform_device *pdev) penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED; } + penv->snoc_wcnss = devm_clk_get(&penv->pdev->dev, "snoc_wcnss"); + if (IS_ERR(penv->snoc_wcnss)) { + pr_err("%s: couldn't get snoc_wcnss\n", __func__); + penv->snoc_wcnss = NULL; + } else { + if (of_property_read_u32(pdev->dev.of_node, + "qcom,snoc-wcnss-clock-freq", + &penv->snoc_wcnss_clock_freq)) { + pr_debug("%s: wcnss snoc clock frequency is not defined\n", + __func__); + devm_clk_put(&penv->pdev->dev, penv->snoc_wcnss); + penv->snoc_wcnss = NULL; + } + } + if (penv->wlan_config.is_pronto_vadc) { penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss"); @@ -3191,6 +3208,38 @@ fail: return ret; } +/* Driver requires to directly vote the snoc clocks + * To enable and disable snoc clock, it call + * wcnss_snoc_vote function + */ +void wcnss_snoc_vote(bool clk_chk_en) +{ + int rc; + + if (!penv->snoc_wcnss) { + pr_err("%s: couldn't get clk snoc_wcnss\n", __func__); + return; + } + + if (clk_chk_en) { + rc = clk_set_rate(penv->snoc_wcnss, + penv->snoc_wcnss_clock_freq); + if (rc) { + pr_err("%s: snoc_wcnss_clk-clk_set_rate failed =%d\n", + __func__, rc); + return; + } + + if (clk_prepare_enable(penv->snoc_wcnss)) { + pr_err("%s: snoc_wcnss clk enable failed\n", __func__); + return; + } + } else { + clk_disable_unprepare(penv->snoc_wcnss); + } +} +EXPORT_SYMBOL(wcnss_snoc_vote); + /* wlan prop driver cannot invoke cancel_work_sync * function directly, so to invoke this function it * call wcnss_flush_work function diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index c93364b861d9..341eb74a9f4b 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 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 @@ -74,6 +74,7 @@ enum { #define HAVE_WCNSS_CAL_DOWNLOAD 1 #define HAVE_CBC_DONE 1 #define HAVE_WCNSS_RX_BUFF_COUNT 1 +#define HAVE_WCNSS_SNOC_HIGH_FREQ_VOTING 1 #define WLAN_MAC_ADDR_SIZE (6) #define WLAN_RF_REG_ADDR_START_OFFSET 0x3 #define WLAN_RF_REG_DATA_START_OFFSET 0xf @@ -138,6 +139,7 @@ void wcnss_init_work(struct work_struct *work , void *callbackptr); void wcnss_init_delayed_work(struct delayed_work *dwork , void *callbackptr); int wcnss_get_iris_name(char *iris_version); void wcnss_dump_stack(struct task_struct *task); +void wcnss_snoc_vote(bool clk_chk_en); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); From 6d11c13b4311665ad0b438bf82908577d6d1a32f Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Wed, 2 Aug 2017 12:55:42 +0530 Subject: [PATCH 2/3] wcnss: Add support to read wifi dual band capability The WLAN dual band support vary from target to target and to enable/disable dual band support for a particular target the wcnss platform driver read the wlan hardware qfuse register and export the dual band capability info to wlan host driver to enable/disable this dual band feature. Add export symbol for dual band capability info. CRs-Fixed: 1115909 Change-Id: I7dc26435e3ac0ac1eec71f0e334878b35e25224d Signed-off-by: Sarada Prasanna Garnayak --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 4 +- drivers/net/wireless/wcnss/wcnss_wlan.c | 50 ++++++++++++++++++- include/linux/wcnss_wlan.h | 2 + 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 63ecac4c68e7..d0855115b6d1 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -12,7 +12,7 @@ Required properties: "riva_ccu_base", "pronto_a2xb_base", "pronto_ccpu_base", "pronto_saw2_base", "wlan_tx_phy_aborts","wlan_brdg_err_source", "wlan_tx_status", "alarms_txctl", "alarms_tactl", - "pronto_mcu_base". + "pronto_mcu_base", "pronto_qfuse". - interupts: Pronto to Apps interrupts for tx done and rx pending. - qcom,pronto-vddmx-supply: regulator to supply pronto pll. - qcom,pronto-vddcx-supply: voltage corner regulator to supply WLAN/BT/FM @@ -47,6 +47,8 @@ using a smaller count for this buffer will reduce the memory usage. - qcom,is-pronto-v3: boolean flag to determine the pronto hardware version in use. subsequently correct workqueue will be used by DXE engine to push frames in TX data path. +- qcom,is-dual-band-disable: boolean flag to determine the WLAN dual band + capability. - qcom,is-pronto-vadc: boolean flag to determine Battery voltage feature support for pronto hardware. - qcom,wcnss-pm : #include #include +#include #include #include @@ -56,6 +57,7 @@ #define WCNSS_PM_QOS_TIMEOUT 15000 #define IS_CAL_DATA_PRESENT 0 #define WAIT_FOR_CBC_IND 2 +#define WCNSS_DUAL_BAND_CAPABILITY_OFFSET BIT(8) /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) @@ -119,6 +121,8 @@ static DEFINE_SPINLOCK(reg_spinlock); #define PRONTO_PMU_COM_CSR_OFFSET 0x1040 #define PRONTO_PMU_SOFT_RESET_OFFSET 0x104C +#define PRONTO_QFUSE_DUAL_BAND_OFFSET 0x0018 + #define A2XB_CFG_OFFSET 0x00 #define A2XB_INT_SRC_OFFSET 0x0c #define A2XB_TSTBUS_CTRL_OFFSET 0x14 @@ -381,6 +385,7 @@ static struct { void __iomem *pronto_saw2_base; void __iomem *pronto_pll_base; void __iomem *pronto_mcu_base; + void __iomem *pronto_qfuse; void __iomem *wlan_tx_status; void __iomem *wlan_tx_phy_aborts; void __iomem *wlan_brdg_err_source; @@ -425,6 +430,7 @@ static struct { struct mutex pm_qos_mutex; struct clk *snoc_wcnss; unsigned int snoc_wcnss_clock_freq; + bool is_dual_band_disabled; } *penv = NULL; static ssize_t wcnss_wlan_macaddr_store(struct device *dev, @@ -597,7 +603,31 @@ void wcnss_pronto_is_a2xb_bus_stall(void *tst_addr, u32 fifo_mask, char *type) } } -/* Log pronto debug registers before sending reset interrupt */ +int wcnss_get_dual_band_capability_info(struct platform_device *pdev) +{ + u32 reg = 0; + struct resource *res; + + res = platform_get_resource_byname( + pdev, IORESOURCE_MEM, "pronto_qfuse"); + if (!res) + return -EINVAL; + + penv->pronto_qfuse = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(penv->pronto_qfuse)) + return -ENOMEM; + + reg = readl_relaxed(penv->pronto_qfuse + + PRONTO_QFUSE_DUAL_BAND_OFFSET); + if (reg & WCNSS_DUAL_BAND_CAPABILITY_OFFSET) + penv->is_dual_band_disabled = true; + else + penv->is_dual_band_disabled = false; + + return 0; +} + +/* Log pronto debug registers during SSR Timeout CB */ void wcnss_pronto_log_debug_regs(void) { void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr; @@ -1685,6 +1715,14 @@ int wcnss_wlan_iris_xo_mode(void) } EXPORT_SYMBOL(wcnss_wlan_iris_xo_mode); +int wcnss_wlan_dual_band_disabled(void) +{ + if (penv && penv->pdev) + return penv->is_dual_band_disabled; + + return -EINVAL; +} +EXPORT_SYMBOL(wcnss_wlan_dual_band_disabled); void wcnss_suspend_notify(void) { @@ -3120,6 +3158,16 @@ wcnss_trigger_config(struct platform_device *pdev) __func__); goto fail_ioremap2; } + + if (of_property_read_bool( + pdev->dev.of_node, "qcom,is-dual-band-disabled")) { + ret = wcnss_get_dual_band_capability_info(pdev); + if (ret) { + pr_err( + "%s: failed to get dual band info\n", __func__); + goto fail_ioremap2; + } + } } penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss"); diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 341eb74a9f4b..78ae70a92753 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -75,6 +75,7 @@ enum { #define HAVE_CBC_DONE 1 #define HAVE_WCNSS_RX_BUFF_COUNT 1 #define HAVE_WCNSS_SNOC_HIGH_FREQ_VOTING 1 +#define HAVE_WCNSS_5G_DISABLE 1 #define WLAN_MAC_ADDR_SIZE (6) #define WLAN_RF_REG_ADDR_START_OFFSET 0x3 #define WLAN_RF_REG_DATA_START_OFFSET 0xf @@ -133,6 +134,7 @@ void wcnss_riva_dump_pmic_regs(void); int wcnss_xo_auto_detect_enabled(void); u32 wcnss_get_wlan_rx_buff_count(void); int wcnss_wlan_iris_xo_mode(void); +int wcnss_wlan_dual_band_disabled(void); void wcnss_flush_work(struct work_struct *work); void wcnss_flush_delayed_work(struct delayed_work *dwork); void wcnss_init_work(struct work_struct *work , void *callbackptr); From cca1739db38ce7c40d518255404c86b6046f5a03 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Wed, 21 Jun 2017 20:43:31 +0530 Subject: [PATCH 3/3] wcnss: Update the wcnss wlan module power up sequence The wcnss wlan module power up sequence has been changed. To add support for the wcnss new power up sequence configured 3.3v external GPIO in wcnss platform driver. Add check for the target to support the 3.3v external gpio for the wcnss power up and routine to control the gpio like gpio init, enable, disable for the device power management in different state of the wcnss wlan device. CRs-Fixed: 2065396 Change-Id: Ie6b79415b670522aa0abee58a23a31cffec76f5a Signed-off-by: Sarada Prasanna Garnayak --- .../devicetree/bindings/wcnss/wcnss-wlan.txt | 6 ++ drivers/net/wireless/wcnss/wcnss_vreg.c | 63 ++++++++++++++- drivers/net/wireless/wcnss/wcnss_wlan.c | 78 ++++++++++++------- include/linux/wcnss_wlan.h | 7 ++ 4 files changed, 125 insertions(+), 29 deletions(-) diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index d0855115b6d1..46cbc5206be4 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -64,6 +64,10 @@ support for pronto hardware. to use for VBATT feature. - qcom,has-a2xb-split-reg: boolean flag to determine A2xb split timeout limit register is available or not. +- qcom,wcn-external-gpio-support: boolean flag to determine 3.3v gpio support +for pronto hardware for a target. +- qcom,wcn-external-gpio: The wcnss wlan module 3.3v external GPIO for +the pronto hardware. Example: @@ -85,6 +89,8 @@ Example: gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>; + qcom,wcn-external-gpio = <&msmgpio 64 0>; + qcom,wcn-external-gpio-support; qcom,has-48mhz-xo; qcom,is-pronto-vt; qcom,wlan-rx-buff-count = <512>; diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c index 4f4ee15b133f..613f6fbc786c 100644 --- a/drivers/net/wireless/wcnss/wcnss_vreg.c +++ b/drivers/net/wireless/wcnss/wcnss_vreg.c @@ -101,6 +101,45 @@ enum { IRIS_3610 }; +static int wcnss_external_gpio_set_state(bool state) +{ + int ret; + struct wcnss_wlan_config *cfg = wcnss_get_wlan_config(); + + if (!cfg) + return -EINVAL; + + if (state) { + ret = gpio_request(cfg->wcn_external_gpio, + WCNSS_EXTERNAL_GPIO_NAME); + if (ret) { + pr_err("%s: Can't get GPIO %s, ret = %d\n", + __func__, WCNSS_EXTERNAL_GPIO_NAME, ret); + return ret; + } + + ret = gpio_direction_output(cfg->wcn_external_gpio, + WCNSS_EXTERNAL_GPIO_DIR_OUT); + if (ret) { + pr_err("%s: Can't set GPIO %s direction, ret = %d\n", + __func__, WCNSS_EXTERNAL_GPIO_NAME, ret); + gpio_free(cfg->wcn_external_gpio); + return ret; + } + + gpio_set_value(cfg->wcn_external_gpio, + WCNSS_EXTERNAL_GPIO_HIGH); + } else { + gpio_set_value(cfg->wcn_external_gpio, WCNSS_EXTERNAL_GPIO_LOW); + gpio_free(cfg->wcn_external_gpio); + } + + pr_debug("%s: %d gpio is now %s\n", __func__, + cfg->wcn_external_gpio, + state ? "enabled" : "disabled"); + + return 0; +} int xo_auto_detect(u32 reg) { @@ -417,6 +456,12 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size, if (regulators[i].state == VREG_NULL_CONFIG) continue; + if (cfg->wcn_external_gpio_support) { + if (!memcmp(regulators[i].name, VDD_PA, + sizeof(VDD_PA))) + continue; + } + /* Remove PWM mode */ if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) { rc = regulator_set_load(regulators[i].regulator, 0); @@ -478,7 +523,13 @@ static int wcnss_vregs_on(struct device *dev, } for (i = 0; i < size; i++) { - /* Get regulator source */ + if (cfg->wcn_external_gpio_support) { + if (!memcmp(regulators[i].name, VDD_PA, + sizeof(VDD_PA))) + continue; + } + + /* Get regulator source */ regulators[i].regulator = regulator_get(dev, regulators[i].name); if (IS_ERR(regulators[i].regulator)) { @@ -622,6 +673,12 @@ int wcnss_wlan_power(struct device *dev, down(&wcnss_power_on_lock); if (on) { + if (cfg->wcn_external_gpio_support) { + rc = wcnss_external_gpio_set_state(true); + if (rc) + return rc; + } + /* RIVA regulator settings */ rc = wcnss_core_vregs_on(dev, hw_type, cfg); @@ -644,6 +701,8 @@ int wcnss_wlan_power(struct device *dev, } else if (is_power_on) { is_power_on = false; + if (cfg->wcn_external_gpio_support) + wcnss_external_gpio_set_state(false); configure_iris_xo(dev, cfg, WCNSS_WLAN_SWITCH_OFF, NULL); wcnss_iris_vregs_off(hw_type, cfg); @@ -660,6 +719,8 @@ fail_iris_on: wcnss_core_vregs_off(hw_type, cfg); fail_wcnss_on: + if (cfg->wcn_external_gpio_support) + wcnss_external_gpio_set_state(false); up(&wcnss_power_on_lock); return rc; } diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 52095bb3c502..4a08979c249b 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -2757,23 +2757,42 @@ wcnss_trigger_config(struct platform_device *pdev) int is_pronto_vadc; int is_pronto_v3; int pil_retry = 0; - int has_pronto_hw = of_property_read_bool(pdev->dev.of_node, - "qcom,has-pronto-hw"); + struct wcnss_wlan_config *wlan_cfg = &penv->wlan_config; + struct device_node *node = (&pdev->dev)->of_node; + int has_pronto_hw = of_property_read_bool(node, "qcom,has-pronto-hw"); - is_pronto_vadc = of_property_read_bool(pdev->dev.of_node, - "qcom,is-pronto-vadc"); + is_pronto_vadc = of_property_read_bool(node, "qcom,is-pronto-vadc"); + is_pronto_v3 = of_property_read_bool(node, "qcom,is-pronto-v3"); - is_pronto_v3 = of_property_read_bool(pdev->dev.of_node, - "qcom,is-pronto-v3"); + penv->is_vsys_adc_channel = + of_property_read_bool(node, "qcom,has-vsys-adc-channel"); + penv->is_a2xb_split_reg = + of_property_read_bool(node, "qcom,has-a2xb-split-reg"); - penv->is_vsys_adc_channel = of_property_read_bool(pdev->dev.of_node, - "qcom,has-vsys-adc-channel"); + wlan_cfg->wcn_external_gpio_support = + of_property_read_bool(node, "qcom,wcn-external-gpio-support"); + if (wlan_cfg->wcn_external_gpio_support) { + if (of_find_property(node, WCNSS_EXTERNAL_GPIO_NAME, NULL)) { + wlan_cfg->wcn_external_gpio = + of_get_named_gpio( + pdev->dev.of_node, + WCNSS_EXTERNAL_GPIO_NAME, + 0); + if (!gpio_is_valid(wlan_cfg->wcn_external_gpio)) { + pr_err("%s: Invalid %s num defined in DT\n", + __func__, WCNSS_EXTERNAL_GPIO_NAME); + ret = -EINVAL; + goto fail; + } + } else { + pr_err("%s: %s prop not defined in DT node\n", + __func__, WCNSS_EXTERNAL_GPIO_NAME); + goto fail; + } + } - penv->is_a2xb_split_reg = of_property_read_bool(pdev->dev.of_node, - "qcom,has-a2xb-split-reg"); - - if (of_property_read_u32(pdev->dev.of_node, - "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) { + if (of_property_read_u32(node, "qcom,wlan-rx-buff-count", + &penv->wlan_rx_buff_count)) { penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT; } @@ -2834,15 +2853,18 @@ wcnss_trigger_config(struct platform_device *pdev) goto fail; } - index++; - ret = wcnss_dt_parse_vreg_level(&pdev->dev, index, - "qcom,iris-vddpa-current", - "qcom,iris-vddpa-voltage-level", - penv->wlan_config.iris_vlevel); - - if (ret) { - dev_err(&pdev->dev, "error reading voltage-level property\n"); - goto fail; + if (!wlan_cfg->wcn_external_gpio_support) { + index++; + ret = wcnss_dt_parse_vreg_level( + &pdev->dev, index, + "qcom,iris-vddpa-current", + "qcom,iris-vddpa-voltage-level", + penv->wlan_config.iris_vlevel); + if (ret) { + dev_err(&pdev->dev, + "error reading voltage-level property\n"); + goto fail; + } } index++; @@ -2865,8 +2887,8 @@ wcnss_trigger_config(struct platform_device *pdev) pdata = pdev->dev.platform_data; 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"); + has_48mhz_xo = + of_property_read_bool(node, "qcom,has-48mhz-xo"); } else { has_48mhz_xo = pdata->has_48mhz_xo; } @@ -2877,8 +2899,8 @@ wcnss_trigger_config(struct platform_device *pdev) penv->wlan_config.is_pronto_v3 = is_pronto_v3; if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) { - has_autodetect_xo = of_property_read_bool(pdev->dev.of_node, - "qcom,has-autodetect-xo"); + has_autodetect_xo = + of_property_read_bool(node, "qcom,has-autodetect-xo"); } penv->thermal_mitigation = 0; @@ -3159,8 +3181,8 @@ wcnss_trigger_config(struct platform_device *pdev) goto fail_ioremap2; } - if (of_property_read_bool( - pdev->dev.of_node, "qcom,is-dual-band-disabled")) { + if (of_property_read_bool(node, + "qcom,is-dual-band-disabled")) { ret = wcnss_get_dual_band_capability_info(pdev); if (ret) { pr_err( diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 78ae70a92753..dbde018af4c6 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -20,6 +20,11 @@ #define IRIS_REGULATORS 4 #define PRONTO_REGULATORS 3 +#define WCNSS_EXTERNAL_GPIO_NAME "qcom,wcn-external-gpio" +#define WCNSS_EXTERNAL_GPIO_HIGH 1 +#define WCNSS_EXTERNAL_GPIO_LOW 0 +#define WCNSS_EXTERNAL_GPIO_DIR_OUT 1 + enum wcnss_opcode { WCNSS_WLAN_SWITCH_OFF = 0, WCNSS_WLAN_SWITCH_ON, @@ -38,6 +43,8 @@ struct vregs_level { }; struct wcnss_wlan_config { + bool wcn_external_gpio_support; + int wcn_external_gpio; int use_48mhz_xo; int is_pronto_vadc; int is_pronto_v3;