Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84920962 authored by Sarada Prasanna Garnayak's avatar Sarada Prasanna Garnayak
Browse files

net: cnss: add fixed regulator support for wlan enable pin



The QCA wlan chipset uses tlmm, msm and pmic gpio for the WLAN_EN
signal pin. The tlmm or msm gpio uses pinctrl or gpio library for
configuring the sleep/active state runtime.

The pmic gpio runtime configuration is not feasible using gpio
library or pinctrl framework. Convert the pmic gpio to fixed
regulator to runtime control(enable/disable) via regulator framework.

CRs-Fixed: 1040537
Change-Id: Ie74a659f309f248d335e03ca7a0a00244e9715b4
Signed-off-by: default avatarSarada Prasanna Garnayak <sgarna@codeaurora.org>
parent 79dd32e0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -44,6 +44,9 @@ Optional properties:
                         which should be drived depending on platforms
  - qcom,is-dual-wifi-enabled: Boolean property to control wlan enable(wlan-en)
                               gpio on dual-wifi platforms.
  - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174 specifications.
  - qcom,wlan-en-vreg-support: Boolean property to decide the whether the WLAN_EN pin
				is a gpio or fixed regulator.

Example:

+141 −91
Original line number Diff line number Diff line
@@ -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;
@@ -291,6 +294,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;
@@ -574,6 +588,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)
{
@@ -680,14 +713,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)) {
@@ -717,8 +807,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)) {
@@ -763,8 +852,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)) {
@@ -785,8 +873,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)) {
@@ -816,13 +903,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)) {
@@ -845,68 +929,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;
	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;
		}

	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 (!penv->wlan_en_vreg_support) {
		ret = cnss_get_wlan_enable_gpio(gpio_info, pdev);
		if (ret) {
		pr_err("%s: pinctrl init failed!\n", __func__);
		goto err_pinctrl_init;
			pr_err(
			"%s:Failed to config the WLAN_EN gpio\n", __func__);
			goto err_gpio_wlan_en;
		}
	}
	vreg_info->state = VREG_ON;

	ret = cnss_wlan_gpio_init(gpio_info);
	ret = cnss_get_wlan_bootstrap_gpio(pdev);
	if (ret) {
		pr_err("gpio init failed\n");
		goto err_gpio_init;
		pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__);
		goto err_gpio_wlan_bootstrap;
	}

	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;
		}
	}
end:
	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;
@@ -965,7 +1022,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);
@@ -1559,7 +1616,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;
@@ -1618,7 +1674,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) {
@@ -2243,8 +2299,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__);
@@ -2329,8 +2384,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++;
@@ -2357,7 +2411,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__);
@@ -2440,8 +2494,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");
}
@@ -2553,8 +2606,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");

@@ -2587,8 +2639,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__);
@@ -2648,7 +2699,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__);
@@ -2835,8 +2886,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) {
@@ -3031,7 +3085,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:
@@ -3042,8 +3096,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);

@@ -3064,7 +3116,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();
@@ -3559,8 +3611,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;
}

@@ -3573,8 +3624,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);