ASoC: Add Euro usb-c analog support for sdm670 internal codec

Euro usb-c analog support is not present in machine driver
for sdm670. Add support for corresponding gpio
so that usb-c analog headset is reported correctly.

CRs-Fixed: 2164436
Change-Id: I4bf73a9f13b7b8193289706ac21f96c557503fd8
Signed-off-by: Vatsal Bucha <vbucha@codeaurora.org>
diff --git a/asoc/sdm660-common.c b/asoc/sdm660-common.c
index ccfe528..f2376b4 100644
--- a/asoc/sdm660-common.c
+++ b/asoc/sdm660-common.c
@@ -2824,27 +2824,123 @@
 	return ret;
 }
 
+
+static bool msm_usbc_swap_gnd_mic(struct snd_soc_codec *codec, bool active)
+{
+	int value = 0;
+	bool ret = false;
+	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->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;
+		}
+	}
+
+	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\n",
+			__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)
 {
 	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;
 
-	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(
+	if (!mbhc_cfg.enable_usbc_analog) {
+		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(
+			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);
+		} 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);
 	}
-	pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
-	return true;
+	return ret;
 }
 
 static int msm_populate_dai_link_component_of_node(
@@ -3256,6 +3352,7 @@
 	const char *mclk = "qcom,msm-mclk-freq";
 	int ret = -EINVAL, id;
 	const struct of_device_id *match;
+	const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported";
 
 	pdata = devm_kzalloc(&pdev->dev,
 			     sizeof(struct msm_asoc_mach_data),
@@ -3340,6 +3437,9 @@
 		mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic;
 	}
 
+	if (of_find_property(pdev->dev.of_node, usb_c_dt, NULL))
+		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",