diff --git a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi index ff128acb376a..316859a65801 100644 --- a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi @@ -1449,7 +1449,7 @@ }; cnss_pins { - cnss_default: cnss_default { + cnss_bootstrap_active: cnss_bootstrap_active { mux { pins = "gpio46"; function = "gpio"; @@ -1458,6 +1458,20 @@ config { pins = "gpio46"; drive-strength = <16>; + output-high; + bias-pull-up; + }; + }; + cnss_bootstrap_sleep: cnss_bootstrap_sleep { + mux { + pins = "gpio46"; + function = "gpio"; + }; + + config { + pins = "gpio46"; + drive-strength = <2>; + output-low; bias-pull-down; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index c1a6d1fc4b4f..f5e059484c95 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -2335,15 +2335,17 @@ qcom,cnss { compatible = "qcom,cnss"; wlan-bootstrap-gpio = <&tlmm 46 0>; - wlan-en-gpio = <&pm8994_gpios 8 0>; + vdd-wlan-en-supply = <&wlan_en_vreg>; vdd-wlan-supply = <&rome_vreg>; vdd-wlan-io-supply = <&pm8994_s4>; vdd-wlan-xtal-supply = <&pm8994_l30>; vdd-wlan-core-supply = <&pm8994_s3>; wlan-ant-switch-supply = <&pm8994_l18_pin_ctrl>; + qcom,wlan-en-vreg-support; qcom,notify-modem-status; - pinctrl-names = "default"; - pinctrl-0 = <&cnss_default>; + pinctrl-names = "bootstrap_active", "bootstrap_sleep"; + pinctrl-0 = <&cnss_bootstrap_active>; + pinctrl-1 = <&cnss_bootstrap_sleep>; qcom,wlan-rc-num = <0>; qcom,wlan-ramdump-dynamic = <0x200000>; diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index d150c2dd0f0f..af92f00ca56e 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -83,6 +83,7 @@ #define QCA6180_DEVICE_ID (0x0041) #define QCA6180_REV_ID_OFFSET (0x08) +#define WLAN_EN_VREG_NAME "vdd-wlan-en" #define WLAN_VREG_NAME "vdd-wlan" #define WLAN_VREG_IO_NAME "vdd-wlan-io" #define WLAN_VREG_XTAL_NAME "vdd-wlan-xtal" @@ -156,6 +157,7 @@ struct cnss_wlan_gpio_info { }; struct cnss_wlan_vreg_info { + struct regulator *wlan_en_reg; struct regulator *wlan_reg; struct regulator *soc_swreg; struct regulator *ant_switch; @@ -238,6 +240,7 @@ static struct cnss_data { dma_addr_t smmu_iova_start; size_t smmu_iova_len; struct cnss_wlan_vreg_info vreg_info; + bool wlan_en_vreg_support; struct cnss_wlan_gpio_info gpio_info; bool pcie_link_state; bool pcie_link_down_ind; @@ -293,6 +296,17 @@ module_param(pcie_link_down_panic, uint, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(pcie_link_down_panic, "Trigger kernel panic when PCIe link down is detected"); +static void cnss_put_wlan_enable_gpio(void) +{ + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + + if (penv->wlan_en_vreg_support) + regulator_put(vreg_info->wlan_en_reg); + else + gpio_free(gpio_info->num); +} + static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info) { int ret; @@ -576,6 +590,25 @@ static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state) info->name, info->state ? "enabled" : "disabled"); } +static int cnss_configure_wlan_en_gpio(bool state) +{ + int ret = 0; + struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; + struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + + if (penv->wlan_en_vreg_support) { + if (state) + ret = regulator_enable(vreg_info->wlan_en_reg); + else + ret = regulator_disable(vreg_info->wlan_en_reg); + } else { + cnss_wlan_gpio_set(gpio_info, state); + } + + msleep(WLAN_ENABLE_DELAY); + return ret; +} + static int cnss_pinctrl_init(struct cnss_wlan_gpio_info *gpio_info, struct platform_device *pdev) { @@ -682,14 +715,71 @@ end: return ret; } +static int cnss_get_wlan_enable_gpio( + struct cnss_wlan_gpio_info *gpio_info, + struct platform_device *pdev) +{ + int ret = 0; + struct device *dev = &pdev->dev; + + if (!of_find_property(dev->of_node, gpio_info->name, NULL)) { + gpio_info->prop = false; + return -ENODEV; + } + + gpio_info->prop = true; + ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0); + if (ret >= 0) { + gpio_info->num = ret; + } else { + if (ret == -EPROBE_DEFER) + pr_debug("get WLAN_EN GPIO probe defer\n"); + else + pr_err( + "can't get gpio %s ret %d", gpio_info->name, ret); + } + + ret = cnss_pinctrl_init(gpio_info, pdev); + if (ret) + pr_debug("%s: pinctrl init failed!\n", __func__); + + ret = cnss_wlan_gpio_init(gpio_info); + if (ret) + pr_err("gpio init failed\n"); + + return ret; +} + +static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev) +{ + int ret = 0; + struct device_node *node = (&pdev->dev)->of_node; + + if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL)) + return ret; + + penv->wlan_bootstrap_gpio = + of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0); + if (penv->wlan_bootstrap_gpio > 0) { + ret = cnss_wlan_bootstrap_gpio_init(); + } else { + ret = penv->wlan_bootstrap_gpio; + pr_err( + "%s: Can't get GPIO %s, ret = %d", + __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret); + } + + return ret; +} + static int cnss_wlan_get_resources(struct platform_device *pdev) { int ret = 0; struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; + struct device_node *node = pdev->dev.of_node; - if (of_get_property(pdev->dev.of_node, - WLAN_VREG_CORE_NAME"-supply", NULL)) { + if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) { vreg_info->wlan_reg_core = regulator_get(&pdev->dev, WLAN_VREG_CORE_NAME); if (IS_ERR(vreg_info->wlan_reg_core)) { @@ -719,8 +809,7 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } } - if (of_get_property(pdev->dev.of_node, - WLAN_VREG_IO_NAME"-supply", NULL)) { + if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) { vreg_info->wlan_reg_io = regulator_get(&pdev->dev, WLAN_VREG_IO_NAME); if (!IS_ERR(vreg_info->wlan_reg_io)) { @@ -765,8 +854,7 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) goto err_reg_enable; } - if (of_get_property(pdev->dev.of_node, - WLAN_VREG_SP2T_NAME"-supply", NULL)) { + if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) { vreg_info->wlan_reg_sp2t = regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME); if (!IS_ERR(vreg_info->wlan_reg_sp2t)) { @@ -787,8 +875,7 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } } - if (of_get_property(pdev->dev.of_node, - WLAN_ANT_SWITCH_NAME "-supply", NULL)) { + if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) { vreg_info->ant_switch = regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME); if (!IS_ERR(vreg_info->ant_switch)) { @@ -818,13 +905,10 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) } } - if (of_find_property((&pdev->dev)->of_node, - "qcom,wlan-uart-access", NULL)) + if (of_find_property(node, "qcom,wlan-uart-access", NULL)) penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS; - if (of_get_property(pdev->dev.of_node, - WLAN_SWREG_NAME"-supply", NULL)) { - + if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) { vreg_info->soc_swreg = regulator_get(&pdev->dev, WLAN_SWREG_NAME); if (IS_ERR(vreg_info->soc_swreg)) { @@ -847,68 +931,41 @@ static int cnss_wlan_get_resources(struct platform_device *pdev) penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG; } - vreg_info->state = VREG_ON; - - if (!of_find_property((&pdev->dev)->of_node, gpio_info->name, NULL)) { - gpio_info->prop = false; - goto end; - } - - gpio_info->prop = true; - ret = of_get_named_gpio((&pdev->dev)->of_node, - gpio_info->name, 0); - - if (ret >= 0) { - gpio_info->num = ret; - ret = 0; - } else { - if (ret == -EPROBE_DEFER) - pr_debug("get WLAN_EN GPIO probe defer\n"); - else - pr_err("can't get gpio %s ret %d", - gpio_info->name, ret); - goto err_get_gpio; - } - - ret = cnss_pinctrl_init(gpio_info, pdev); - if (ret) { - pr_err("%s: pinctrl init failed!\n", __func__); - goto err_pinctrl_init; - } - - ret = cnss_wlan_gpio_init(gpio_info); - if (ret) { - pr_err("gpio init failed\n"); - goto err_gpio_init; - } - - if (of_find_property((&pdev->dev)->of_node, - WLAN_BOOTSTRAP_GPIO_NAME, NULL)) { - penv->wlan_bootstrap_gpio = - of_get_named_gpio((&pdev->dev)->of_node, - WLAN_BOOTSTRAP_GPIO_NAME, 0); - if (penv->wlan_bootstrap_gpio > 0) { - ret = cnss_wlan_bootstrap_gpio_init(); - if (ret) - goto err_gpio_init; - } else { - if (ret == -EPROBE_DEFER) { - pr_debug("%s: Get GPIO %s probe defer\n", - __func__, WLAN_BOOTSTRAP_GPIO_NAME); - } else { - pr_err("%s: Can't get GPIO %s, ret = %d", - __func__, WLAN_BOOTSTRAP_GPIO_NAME, - ret); - } - goto err_gpio_init; + penv->wlan_en_vreg_support = + of_property_read_bool(node, "qcom,wlan-en-vreg-support"); + if (penv->wlan_en_vreg_support) { + vreg_info->wlan_en_reg = + regulator_get(&pdev->dev, WLAN_EN_VREG_NAME); + if (IS_ERR(vreg_info->wlan_en_reg)) { + pr_err("%s:wlan_en vreg get failed\n", __func__); + ret = PTR_ERR(vreg_info->wlan_en_reg); + goto err_wlan_en_reg_get; } } -end: + + if (!penv->wlan_en_vreg_support) { + ret = cnss_get_wlan_enable_gpio(gpio_info, pdev); + if (ret) { + pr_err( + "%s:Failed to config the WLAN_EN gpio\n", __func__); + goto err_gpio_wlan_en; + } + } + vreg_info->state = VREG_ON; + + ret = cnss_get_wlan_bootstrap_gpio(pdev); + if (ret) { + pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__); + goto err_gpio_wlan_bootstrap; + } + return ret; -err_gpio_init: -err_pinctrl_init: -err_get_gpio: +err_gpio_wlan_bootstrap: + cnss_put_wlan_enable_gpio(); +err_gpio_wlan_en: +err_wlan_en_reg_get: + vreg_info->wlan_en_reg = NULL; if (vreg_info->soc_swreg) regulator_disable(vreg_info->soc_swreg); vreg_info->state = VREG_OFF; @@ -967,7 +1024,7 @@ static void cnss_wlan_release_resources(void) if (penv->wlan_bootstrap_gpio > 0) gpio_free(penv->wlan_bootstrap_gpio); - gpio_free(gpio_info->num); + cnss_put_wlan_enable_gpio(); gpio_info->state = WLAN_EN_LOW; gpio_info->prop = false; cnss_wlan_vreg_set(vreg_info, VREG_OFF); @@ -1553,7 +1610,6 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, { int ret = 0; struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info; - struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; void *cpu_addr; dma_addr_t dma_handle; struct codeswap_codeseg_info *cnss_seg_info = NULL; @@ -1612,7 +1668,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, penv->pcie_link_state = PCIE_LINK_DOWN; } - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (ret) { @@ -2259,8 +2315,7 @@ again: msleep(WLAN_BOOTSTRAP_DELAY); } - cnss_wlan_gpio_set(gpio_info, WLAN_EN_HIGH); - msleep(WLAN_ENABLE_DELAY); + cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); if (!pdev) { pr_debug("%s: invalid pdev. register pci device\n", __func__); @@ -2343,8 +2398,7 @@ again: cnss_get_pci_dev_bus_number(pdev), pdev, PM_OPTIONS); penv->pcie_link_state = PCIE_LINK_DOWN; - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); - msleep(WLAN_ENABLE_DELAY); + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); msleep(POWER_ON_DELAY); probe_again++; @@ -2371,7 +2425,7 @@ err_pcie_link_up: } err_pcie_reg: - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { pr_err("%d: Unregistering PCI device\n", __LINE__); @@ -2452,8 +2506,7 @@ void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver) cut_power: penv->driver = NULL; - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); - + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) pr_err("wlan vreg OFF failed\n"); } @@ -2565,8 +2618,7 @@ static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop) } cut_power: - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); - + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); if (cnss_wlan_vreg_set(vreg_info, VREG_OFF)) pr_err("cnss: Failed to set WLAN VREG_OFF!\n"); @@ -2599,8 +2651,7 @@ static int cnss_powerup(const struct subsys_desc *subsys) } msleep(POWER_ON_DELAY); - cnss_wlan_gpio_set(gpio_info, WLAN_EN_HIGH); - msleep(WLAN_ENABLE_DELAY); + cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); if (!pdev) { pr_err("%d: invalid pdev\n", __LINE__); @@ -2660,7 +2711,7 @@ err_wlan_reinit: penv->pcie_link_state = PCIE_LINK_DOWN; err_pcie_link_up: - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { pr_err("%d: Unregistering pci device\n", __LINE__); @@ -2848,8 +2899,11 @@ static int cnss_probe(struct platform_device *pdev) if (ret) goto err_get_wlan_res; - cnss_wlan_gpio_set(&penv->gpio_info, WLAN_EN_HIGH); - msleep(WLAN_ENABLE_DELAY); + ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); + if (ret) { + pr_err("%s: Failed to enable WLAN enable gpio\n", __func__); + goto err_get_rc; + } ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num); if (ret) { @@ -3044,7 +3098,7 @@ err_subsys_reg: err_esoc_reg: err_pcie_enumerate: err_get_rc: - cnss_wlan_gpio_set(&penv->gpio_info, WLAN_EN_LOW); + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_release_resources(); err_get_wlan_res: @@ -3055,8 +3109,6 @@ err_get_wlan_res: static int cnss_remove(struct platform_device *pdev) { - struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info; - unregister_pm_notifier(&cnss_pm_notifier); device_remove_file(&pdev->dev, &dev_attr_fw_image_setup); @@ -3077,7 +3129,7 @@ static int cnss_remove(struct platform_device *pdev) } } - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); if (penv->wlan_bootstrap_gpio > 0) gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW); cnss_wlan_release_resources(); @@ -3578,8 +3630,7 @@ static int __cnss_pcie_power_up(struct device *dev) msleep(WLAN_BOOTSTRAP_DELAY); } - cnss_wlan_gpio_set(gpio_info, WLAN_EN_HIGH); - msleep(WLAN_ENABLE_DELAY); + cnss_configure_wlan_en_gpio(WLAN_EN_HIGH); return 0; } @@ -3592,8 +3643,7 @@ static int __cnss_pcie_power_down(struct device *dev) vreg_info = &penv->vreg_info; gpio_info = &penv->gpio_info; - cnss_wlan_gpio_set(gpio_info, WLAN_EN_LOW); - + cnss_configure_wlan_en_gpio(WLAN_EN_LOW); if (penv->wlan_bootstrap_gpio > 0) gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);