diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt index 1a1ea6289bbf63a74a4c8770eb40c266e96022ad..615eae840e082a0a2ca3e159113550b59134cba2 100644 --- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt +++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt @@ -26,6 +26,8 @@ Required properties: - 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 - qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs. +- pinctrl-<n> : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt +- pinctrl-names : Names corresponding to the numbered pinctrl states Optional properties: - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect @@ -56,4 +58,8 @@ Example: qcom,has-48mhz-xo; qcom,has-pronto-hw; qcom,wcnss-adc_tm = <&pm8226_adc_tm>; + + pinctrl-names = "wcnss_default", "wcnss_sleep"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; }; diff --git a/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi index 9f0aa72677d5ff84e3e2fe9db8951ac5f5aab23f..78c091e283589232980ac233bac2e915b13dbaa1 100644 --- a/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi @@ -433,6 +433,7 @@ drive-strength = <3>; /* 3 MA */ }; }; + pmx_mdss: pmx_mdss { label = "mdss-pins"; mdss_dsi_active: active { @@ -447,6 +448,25 @@ }; }; + wcnss_pmux: wcnss_pmux { + /* Uses general purpose pins */ + qcom,pins = <&gp 40>, <&gp 41>, + <&gp 42>, <&gp 43>, + <&gp 44>; + qcom,num-grp-pins = <5>; + qcom,pin-func = <1>; + label = "wcnss_pins"; + /* Active configuration of bus pins */ + wcnss_default: wcnss_default { + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + wcnss_sleep: wcnss_sleep { + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + /* CoreSight */ tpiu_seta_1 { qcom,pins = <&gp 8>; diff --git a/arch/arm/boot/dts/qcom/msm8916.dtsi b/arch/arm/boot/dts/qcom/msm8916.dtsi index 8b0c7850514a78e77258693f8f8af3a1ab9f4129..ec04d2d162107192caaaa0467102284ce48d77e0 100644 --- a/arch/arm/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916.dtsi @@ -1150,6 +1150,10 @@ qcom,iris-vddpa-supply = <&pm8916_l9>; qcom,iris-vdddig-supply = <&pm8916_l5>; + pinctrl-names = "wcnss_default", "wcnss_sleep"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; + qcom,has-autodetect-xo; qcom,has-pronto-hw; }; diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index af75b8af7f6937ef084ea6945f03615435ad1c1f..c7af923c653bd5c238bf3be0f1a24ea146e90d37 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -35,6 +35,7 @@ #include <linux/rwsem.h> #include <linux/mfd/pm8xxx/misc.h> #include <linux/qpnp/qpnp-adc.h> +#include <linux/pinctrl/consumer.h> #include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_notif.h> @@ -52,6 +53,9 @@ #define VERSION "1.01" #define WCNSS_PIL_DEVICE "wcnss" +#define WCNSS_PINCTRL_STATE_DEFAULT "wcnss_default" +#define WCNSS_PINCTRL_STATE_SLEEP "wcnss_sleep" + /* module params */ #define WCNSS_CONFIG_UNSPECIFIED (-1) #define UINT32_MAX (0xFFFFFFFFU) @@ -384,6 +388,10 @@ static struct { u16 unsafe_ch_count; u16 unsafe_ch_list[WCNSS_MAX_CH_NUM]; void *wcnss_notif_hdle; + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + int use_pinctrl; } *penv = NULL; static ssize_t wcnss_wlan_macaddr_store(struct device *dev, @@ -922,14 +930,91 @@ static void wcnss_smd_notify_event(void *data, unsigned int event) } static int -wcnss_pronto_gpios_config(struct device *dev, bool enable) +wcnss_pinctrl_set_state(bool active) +{ + struct pinctrl_state *pin_state; + int ret; + + pr_debug("%s: Set GPIO state : %d\n", __func__, active); + + pin_state = active ? penv->gpio_state_active + : penv->gpio_state_suspend; + + if (!IS_ERR_OR_NULL(pin_state)) { + ret = pinctrl_select_state(penv->pinctrl, pin_state); + if (ret < 0) { + pr_err("%s: can not set %s pins\n", __func__, + active ? WCNSS_PINCTRL_STATE_DEFAULT + : WCNSS_PINCTRL_STATE_SLEEP); + return ret; + } + } else { + pr_err("%s: invalid '%s' pinstate\n", __func__, + active ? WCNSS_PINCTRL_STATE_DEFAULT + : WCNSS_PINCTRL_STATE_SLEEP); + return PTR_ERR(pin_state); + } + + return 0; +} + +static int +wcnss_pinctrl_init(struct platform_device *pdev) +{ + /* Get pinctrl if target uses pinctrl */ + penv->pinctrl = devm_pinctrl_get(&pdev->dev); + + if (IS_ERR_OR_NULL(penv->pinctrl)) { + pr_err("%s: failed to get pinctrl\n", __func__); + return PTR_ERR(penv->pinctrl); + } + + penv->gpio_state_active + = pinctrl_lookup_state(penv->pinctrl, + WCNSS_PINCTRL_STATE_DEFAULT); + + if (IS_ERR_OR_NULL(penv->gpio_state_active)) { + pr_err("%s: can not get default pinstate\n", __func__); + return PTR_ERR(penv->gpio_state_active); + } + + penv->gpio_state_suspend + = pinctrl_lookup_state(penv->pinctrl, + WCNSS_PINCTRL_STATE_SLEEP); + + if (IS_ERR_OR_NULL(penv->gpio_state_suspend)) { + pr_warn("%s: can not get sleep pinstate\n", __func__); + return PTR_ERR(penv->gpio_state_suspend); + } + + return 0; +} + +static int +wcnss_pronto_gpios_config(struct platform_device *pdev, bool enable) { int rc = 0; int i, j; int WCNSS_WLAN_NUM_GPIOS = 5; + /* Use Pinctrl to configure 5 wire GPIOs */ + rc = wcnss_pinctrl_init(pdev); + if (rc) { + pr_err("%s: failed to get pin resources\n", __func__); + penv->pinctrl = NULL; + goto gpio_probe; + } else { + rc = wcnss_pinctrl_set_state(true); + if (rc) + pr_err("%s: failed to set pin state\n", + __func__); + penv->use_pinctrl = true; + return rc; + } + +gpio_probe: for (i = 0; i < WCNSS_WLAN_NUM_GPIOS; i++) { - int gpio = of_get_gpio(dev->of_node, i); + int gpio = of_get_gpio(pdev->dev.of_node, i); if (enable) { rc = gpio_request(gpio, "wcnss_wlan"); if (rc) { @@ -940,12 +1025,11 @@ wcnss_pronto_gpios_config(struct device *dev, bool enable) } 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); + int gpio = of_get_gpio(pdev->dev.of_node, i); gpio_free(gpio); } return rc; @@ -2105,7 +2189,7 @@ wcnss_trigger_config(struct platform_device *pdev) 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"); + "qcom,has-autodetect-xo"); } penv->thermal_mitigation = 0; @@ -2124,7 +2208,7 @@ wcnss_trigger_config(struct platform_device *pdev) } ret = wcnss_gpios_config(penv->gpios_5wire, true); } else - ret = wcnss_pronto_gpios_config(&pdev->dev, true); + ret = wcnss_pronto_gpios_config(pdev, true); if (ret) { dev_err(&pdev->dev, "WCNSS gpios config failed.\n"); @@ -2415,10 +2499,12 @@ fail_ioremap2: fail_ioremap: wake_lock_destroy(&penv->wcnss_wake_lock); fail_res: - if (has_pronto_hw) - wcnss_pronto_gpios_config(&pdev->dev, false); - else + if (!has_pronto_hw) wcnss_gpios_config(penv->gpios_5wire, false); + else if (penv->use_pinctrl) + wcnss_pinctrl_set_state(false); + else + wcnss_pronto_gpios_config(pdev, false); fail_gpio_res: penv = NULL; return ret;