Merge "ARM: dts: msm: Add EN2 gpio for mic/gnd swap for SDM845 QRD target"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index e0ab31f..3a09b28 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -2256,8 +2256,8 @@
 - qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target
 - qcom,msm-mbhc-usbc-audio-supported : Property to specify if analog audio feature is
 				       enabled or not.
-- qcom,usbc-analog-en1_gpio : EN1 GPIO to enable USB type-C analog audio
-- qcom,usbc-analog-en2_n_gpio : EN2 GPIO to enable USB type-C analog audio
+- qcom,usbc-analog-en1-gpio : EN1 GPIO to enable USB type-C analog audio
+- qcom,usbc-analog-en2-gpio : EN2 GPIO to enable USB type-C analog audio
 - qcom,usbc-analog-force_detect_gpio : Force detect GPIO to enable USB type-C analog audio
 
 Example:
@@ -2333,8 +2333,8 @@
 		qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrLeft",
 					  "SpkrRight", "SpkrLeft";
 		qcom,msm-mbhc-usbc-audio-supported = <1>;
-		qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
-		qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>;
+		qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>;
+		qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
 		qcom,usbc-analog-force_detect_gpio = <&wcd_usbc_analog_f_gpio>;
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index 628b6cc..709c89d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -78,6 +78,9 @@
 		qcom,hph-en0-gpio = <&tavil_hph_en0>;
 		qcom,hph-en1-gpio = <&tavil_hph_en1>;
 		qcom,tavil-mclk-clk-freq = <9600000>;
+
+		qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>;
+
 		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
 				<&loopback>, <&compress>, <&hostless>,
 				<&afe>, <&lsm>, <&routing>, <&compr>,
@@ -136,6 +139,18 @@
 				<&wsa881x_0213>, <&wsa881x_0214>;
 		qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
 					  "SpkrLeft", "SpkrRight";
+
+		qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wcd_usbc_analog_en2_active>;
+		pinctrl-1 = <&wcd_usbc_analog_en2_idle>;
+	};
+
+	wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 {
+		compatible = "qcom,msm-cdc-pinctrl";
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wcd_usbc_analog_en1_active>;
+		pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
 	};
 
 	wcd9xxx_intc: wcd9xxx-irq {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 1fbd8a2..9946a25 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -299,6 +299,63 @@
 			};
 		};
 
+		/* USB C analog configuration */
+		wcd_usbc_analog_en1 {
+			wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle {
+				mux {
+					pins = "gpio49";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio49";
+					drive-strength = <2>;
+					bias-pull-down;
+					output-low;
+				};
+			};
+
+			wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active {
+				mux {
+					pins = "gpio49";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio49";
+					drive-strength = <2>;
+					bias-disable;
+					output-high;
+				};
+			};
+		};
+
+		wcd_usbc_analog_en2 {
+			wcd_usbc_analog_en2_idle: wcd_usbc_ana_en2_idle {
+				mux {
+					pins = "gpio51";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio51";
+					drive-strength = <2>;
+					bias-pull-down;
+					output-low;
+				};
+			};
+
+			wcd_usbc_analog_en2_active: wcd_usbc_ana_en2_active {
+				mux {
+					pins = "gpio51";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio51";
+					drive-strength = <2>;
+					bias-disable;
+					output-high;
+				};
+			};
+		};
+
 		pri_aux_pcm_clk {
 			pri_aux_pcm_clk_sleep: pri_aux_pcm_clk_sleep {
 				mux {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 4dba65b..bba95a3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -105,6 +105,41 @@
 		qcom,wsa-max-devs = <1>;
 		qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>;
 		qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight";
+
+		qcom,msm-mbhc-usbc-audio-supported = <1>;
+
+		qcom,usbc-analog-en2-gpio = <&tlmm 51 0>;
+		pinctrl-names = "aud_active", "aud_sleep";
+		pinctrl-0 = <&wcd_usbc_analog_en2_active>;
+		pinctrl-1 = <&wcd_usbc_analog_en2_idle>;
+	};
+};
+
+&wcd934x_cdc {
+	wcd: wcd_pinctrl@5 {
+		us_euro_sw_wcd_active: us_euro_sw_wcd_active {
+			mux {
+				pins = "gpio1";
+			};
+
+			config {
+				pins = "gpio1";
+				/delete-property/ output-high;
+				bias-high-impedance;
+			};
+		};
+
+		us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep {
+			mux {
+				pins = "gpio1";
+			};
+
+			config {
+				pins = "gpio1";
+				/delete-property/ output-low;
+				bias-high-impedance;
+			};
+		};
 	};
 };
 
diff --git a/sound/soc/codecs/wcd-mbhc-adc.c b/sound/soc/codecs/wcd-mbhc-adc.c
index 7278431..e44eec9 100644
--- a/sound/soc/codecs/wcd-mbhc-adc.c
+++ b/sound/soc/codecs/wcd-mbhc-adc.c
@@ -729,7 +729,8 @@
 				 * otherwise report unsupported plug
 				 */
 				if (mbhc->mbhc_cfg->swap_gnd_mic &&
-					mbhc->mbhc_cfg->swap_gnd_mic(codec)) {
+					mbhc->mbhc_cfg->swap_gnd_mic(codec,
+					true)) {
 					pr_debug("%s: US_EU gpio present,flip switch\n"
 						, __func__);
 					continue;
diff --git a/sound/soc/codecs/wcd-mbhc-legacy.c b/sound/soc/codecs/wcd-mbhc-legacy.c
index 83023bc..745e2e8 100644
--- a/sound/soc/codecs/wcd-mbhc-legacy.c
+++ b/sound/soc/codecs/wcd-mbhc-legacy.c
@@ -633,7 +633,8 @@
 				 * otherwise report unsupported plug
 				 */
 				if (mbhc->mbhc_cfg->swap_gnd_mic &&
-					mbhc->mbhc_cfg->swap_gnd_mic(codec)) {
+					mbhc->mbhc_cfg->swap_gnd_mic(codec,
+					true)) {
 					pr_debug("%s: US_EU gpio present,flip switch\n"
 						, __func__);
 					continue;
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 510a8dc..ebcb413 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -1460,18 +1460,12 @@
 		if (config->usbc_en1_gpio_p)
 			rc = msm_cdc_pinctrl_select_active_state(
 				config->usbc_en1_gpio_p);
-		if (rc == 0 && config->usbc_en2n_gpio_p)
-			rc = msm_cdc_pinctrl_select_active_state(
-				config->usbc_en2n_gpio_p);
 		if (rc == 0 && config->usbc_force_gpio_p)
 			rc = msm_cdc_pinctrl_select_active_state(
 				config->usbc_force_gpio_p);
 		mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
 	} else {
 		/* no delay is required when disabling GPIOs */
-		if (config->usbc_en2n_gpio_p)
-			msm_cdc_pinctrl_select_sleep_state(
-				config->usbc_en2n_gpio_p);
 		if (config->usbc_en1_gpio_p)
 			msm_cdc_pinctrl_select_sleep_state(
 				config->usbc_en1_gpio_p);
@@ -1490,6 +1484,8 @@
 		}
 
 		mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE;
+		if (mbhc->mbhc_cfg->swap_gnd_mic)
+			mbhc->mbhc_cfg->swap_gnd_mic(mbhc->codec, false);
 	}
 
 	return rc;
@@ -1675,19 +1671,12 @@
 		dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n",
 				__func__);
 		rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
-				"qcom,usbc-analog-en1_gpio",
+				"qcom,usbc-analog-en1-gpio",
 				&config->usbc_en1_gpio,
 				&config->usbc_en1_gpio_p);
 		if (rc)
 			goto err;
 
-		rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg,
-				"qcom,usbc-analog-en2_n_gpio",
-				&config->usbc_en2n_gpio,
-				&config->usbc_en2n_gpio_p);
-		if (rc)
-			goto err;
-
 		if (of_find_property(card->dev->of_node,
 				     "qcom,usbc-analog-force_detect_gpio",
 				     NULL)) {
@@ -1734,12 +1723,6 @@
 		gpio_free(config->usbc_en1_gpio);
 		config->usbc_en1_gpio = 0;
 	}
-	if (config->usbc_en2n_gpio > 0) {
-		dev_dbg(card->dev, "%s free usb_en2 gpio %d\n",
-			__func__, config->usbc_en2n_gpio);
-		gpio_free(config->usbc_en2n_gpio);
-		config->usbc_en2n_gpio = 0;
-	}
 	if (config->usbc_force_gpio > 0) {
 		dev_dbg(card->dev, "%s free usb_force gpio %d\n",
 			__func__, config->usbc_force_gpio);
@@ -1748,8 +1731,6 @@
 	}
 	if (config->usbc_en1_gpio_p)
 		of_node_put(config->usbc_en1_gpio_p);
-	if (config->usbc_en2n_gpio_p)
-		of_node_put(config->usbc_en2n_gpio_p);
 	if (config->usbc_force_gpio_p)
 		of_node_put(config->usbc_force_gpio_p);
 	dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc);
@@ -1790,15 +1771,11 @@
 		/* free GPIOs */
 		if (config->usbc_en1_gpio > 0)
 			gpio_free(config->usbc_en1_gpio);
-		if (config->usbc_en2n_gpio > 0)
-			gpio_free(config->usbc_en2n_gpio);
 		if (config->usbc_force_gpio)
 			gpio_free(config->usbc_force_gpio);
 
 		if (config->usbc_en1_gpio_p)
 			of_node_put(config->usbc_en1_gpio_p);
-		if (config->usbc_en2n_gpio_p)
-			of_node_put(config->usbc_en2n_gpio_p);
 		if (config->usbc_force_gpio_p)
 			of_node_put(config->usbc_force_gpio_p);
 	}
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index 4ea4401..7ed06c3 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -404,10 +404,10 @@
 
 struct usbc_ana_audio_config {
 	int usbc_en1_gpio;
-	int usbc_en2n_gpio;
+	int usbc_en2_gpio;
 	int usbc_force_gpio;
 	struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */
-	struct device_node *usbc_en2n_gpio_p; /* used by pinctrl API */
+	struct device_node *usbc_en2_gpio_p; /* used by pinctrl API */
 	struct device_node *usbc_force_gpio_p; /* used by pinctrl API */
 };
 
@@ -416,7 +416,7 @@
 	void *calibration;
 	bool detect_extn_cable;
 	bool mono_stero_detection;
-	bool (*swap_gnd_mic)(struct snd_soc_codec *codec);
+	bool (*swap_gnd_mic)(struct snd_soc_codec *codec, bool active);
 	bool hs_ext_micbias;
 	bool gnd_det_en;
 	int key_code[WCD_MBHC_KEYCODE_NUM];
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 304bf47..130cc56 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -173,7 +173,9 @@
 struct msm_asoc_mach_data {
 	u32 mclk_freq;
 	int us_euro_gpio; /* used by gpio driver API */
+	int usbc_en2_gpio; /* used by gpio driver API */
 	struct device_node *us_euro_gpio_p; /* used by pinctrl API */
+	struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */
 	struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
 	struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
 	struct snd_info_entry *codec_root;
@@ -3106,27 +3108,126 @@
 	return rc;
 }
 
-static bool msm_swap_gnd_mic(struct snd_soc_codec *codec)
+static bool msm_usbc_swap_gnd_mic(struct snd_soc_codec *codec, bool active)
 {
-	struct snd_soc_card *card = codec->component.card;
-	struct msm_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
 	int value = 0;
+	bool ret = 0;
+	struct snd_soc_card *card = codec->component.card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct pinctrl_state *en2_pinctrl_active;
+	struct pinctrl_state *en2_pinctrl_sleep;
 
-	if (pdata->us_euro_gpio_p) {
-		value = msm_cdc_pinctrl_get_state(pdata->us_euro_gpio_p);
-		if (value)
-			msm_cdc_pinctrl_select_sleep_state(
-							pdata->us_euro_gpio_p);
-		else
-			msm_cdc_pinctrl_select_active_state(
-							pdata->us_euro_gpio_p);
-	} else if (pdata->us_euro_gpio >= 0) {
-		value = gpio_get_value_cansleep(pdata->us_euro_gpio);
-		gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+	if (!pdata->usbc_en2_gpio_p) {
+		if (active) {
+			/* if active and usbc_en2_gpio undefined, get pin */
+			pdata->usbc_en2_gpio_p = devm_pinctrl_get(card->dev);
+			if (IS_ERR_OR_NULL(pdata->usbc_en2_gpio_p)) {
+				dev_err(card->dev,
+					"%s: Can't get EN2 gpio pinctrl:%ld\n",
+					__func__,
+					PTR_ERR(pdata->usbc_en2_gpio_p));
+				pdata->usbc_en2_gpio_p = NULL;
+				return false;
+			}
+		} else
+			/* if not active and usbc_en2_gpio undefined, return */
+			return false;
 	}
-	pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
-	return true;
+
+	pdata->usbc_en2_gpio = of_get_named_gpio(card->dev->of_node,
+				    "qcom,usbc-analog-en2-gpio", 0);
+	if (!gpio_is_valid(pdata->usbc_en2_gpio)) {
+		dev_err(card->dev, "%s, property %s not in node %s",
+			__func__, "qcom,usbc-analog-en2-gpio",
+			card->dev->of_node->full_name);
+		return false;
+	}
+
+	en2_pinctrl_active = pinctrl_lookup_state(
+					pdata->usbc_en2_gpio_p, "aud_active");
+	if (IS_ERR_OR_NULL(en2_pinctrl_active)) {
+		dev_err(card->dev,
+			"%s: Cannot get aud_active pinctrl state:%ld\n",
+			__func__, PTR_ERR(en2_pinctrl_active));
+		ret = false;
+		goto err_lookup_state;
+	}
+
+	en2_pinctrl_sleep = pinctrl_lookup_state(
+					pdata->usbc_en2_gpio_p, "aud_sleep");
+	if (IS_ERR_OR_NULL(en2_pinctrl_sleep)) {
+		dev_err(card->dev,
+			"%s: Cannot get aud_sleep pinctrl state:%ld\n",
+			__func__, PTR_ERR(en2_pinctrl_sleep));
+		ret = false;
+		goto err_lookup_state;
+	}
+
+	/* if active and usbc_en2_gpio_p defined, swap using usbc_en2_gpio_p */
+	if (active) {
+		dev_dbg(codec->dev, "%s: enter\n", __func__);
+		if (pdata->usbc_en2_gpio_p) {
+			value = gpio_get_value_cansleep(pdata->usbc_en2_gpio);
+			if (value)
+				pinctrl_select_state(pdata->usbc_en2_gpio_p,
+							en2_pinctrl_sleep);
+			else
+				pinctrl_select_state(pdata->usbc_en2_gpio_p,
+							en2_pinctrl_active);
+		} else if (pdata->usbc_en2_gpio >= 0) {
+			value = gpio_get_value_cansleep(pdata->usbc_en2_gpio);
+			gpio_set_value_cansleep(pdata->usbc_en2_gpio, !value);
+		}
+		pr_debug("%s: swap select switch %d to %d\n", __func__,
+			value, !value);
+		ret = true;
+	} else {
+		/* if not active, release usbc_en2_gpio_p pin */
+		pinctrl_select_state(pdata->usbc_en2_gpio_p,
+					en2_pinctrl_sleep);
+	}
+
+err_lookup_state:
+	devm_pinctrl_put(pdata->usbc_en2_gpio_p);
+	pdata->usbc_en2_gpio_p = NULL;
+	return ret;
+}
+
+static bool msm_swap_gnd_mic(struct snd_soc_codec *codec, bool active)
+{
+	int value = 0;
+	int ret = 0;
+	struct snd_soc_card *card = codec->component.card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	if (!pdata)
+		return false;
+
+	if (!wcd_mbhc_cfg.enable_usbc_analog) {
+		/* if usbc is not defined, swap using us_euro_gpio_p */
+		if (pdata->us_euro_gpio_p) {
+			value = msm_cdc_pinctrl_get_state(
+						pdata->us_euro_gpio_p);
+			if (value)
+				msm_cdc_pinctrl_select_sleep_state(
+						pdata->us_euro_gpio_p);
+			else
+				msm_cdc_pinctrl_select_active_state(
+						pdata->us_euro_gpio_p);
+		} else if (pdata->us_euro_gpio >= 0) {
+			value = gpio_get_value_cansleep(
+						pdata->us_euro_gpio);
+			gpio_set_value_cansleep(
+					pdata->us_euro_gpio, !value);
+		}
+		pr_debug("%s: swap select switch %d to %d\n", __func__,
+			 value, !value);
+		ret = true;
+	} else {
+		/* if usbc is defined, swap using usbc_en2 */
+		ret = msm_usbc_swap_gnd_mic(codec, active);
+	}
+	return ret;
 }
 
 static int msm_afe_set_config(struct snd_soc_codec *codec)
@@ -6454,6 +6555,7 @@
 	char *mclk_freq_prop_name;
 	const struct of_device_id *match;
 	int ret;
+	const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported";
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -6601,6 +6703,9 @@
 		wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
 	}
 
+	if (of_find_property(pdev->dev.of_node, usb_c_dt, NULL))
+		wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
+
 	ret = msm_prepare_us_euro(card);
 	if (ret)
 		dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",