diff --git a/asoc/sdm660-common.c b/asoc/sdm660-common.c index ccfe528487dd..f2376b4ee29b 100644 --- a/asoc/sdm660-common.c +++ b/asoc/sdm660-common.c @@ -2824,27 +2824,123 @@ static int msm_prepare_us_euro(struct snd_soc_card *card) 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 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) 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 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) 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", diff --git a/asoc/sdm660-common.h b/asoc/sdm660-common.h index 030f5219a963..6c3eefa260e3 100644 --- a/asoc/sdm660-common.h +++ b/asoc/sdm660-common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -93,9 +93,11 @@ enum { struct msm_asoc_mach_data { int us_euro_gpio; /* used by gpio driver API */ + int usbc_en2_gpio; /* used by gpio driver API */ int hph_en1_gpio; int hph_en0_gpio; 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 device_node *pdm_gpio_p; /* used by pinctrl API */