diff --git a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi index 506e37c2349a..a9aeab45745d 100644 --- a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi @@ -53,6 +53,8 @@ "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", "AMIC2", "MIC BIAS2", "MIC BIAS2", "Headset Mic", "AMIC3", "MIC BIAS2", @@ -81,6 +83,8 @@ qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; qcom,us-euro-gpios = <&wcd_us_euro_gpio>; + qcom,hph-en0-gpio = <&hph_en0_gpio>; + qcom,hph-en1-gpio = <&hph_en1_gpio>; qcom,tasha-mclk-clk-freq = <9600000>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, @@ -142,6 +146,20 @@ <&wsa881x_213>, <&wsa881x_214>; qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", "SpkrLeft", "SpkrRight"; + + hph_en0_gpio: msm_cdc_pinctrl@67 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en0_active>; + pinctrl-1 = <&hph_en0_idle>; + }; + + hph_en1_gpio: msm_cdc_pinctrl@68 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en1_active>; + pinctrl-1 = <&hph_en1_idle>; + }; }; sound-tavil { @@ -165,6 +183,8 @@ qcom,audio-routing = "RX_BIAS", "MCLK", "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", "AMIC2", "MIC BIAS2", "MIC BIAS2", "Headset Mic", "AMIC3", "MIC BIAS2", diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi index 436df2410de6..d4a2290c9b0a 100644 --- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi @@ -587,6 +587,60 @@ }; }; + hph_en0_ctrl { + hph_en0_idle: hph_en0_idle { + mux { + pins = "gpio67"; + function = "gpio"; + }; + config { + pins = "gpio67"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + hph_en0_active: hph_en0_active { + mux { + pins = "gpio67"; + function = "gpio"; + }; + config { + pins = "gpio67"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + hph_en1_ctrl { + hph_en1_idle: hph_en1_idle { + mux { + pins = "gpio68"; + function = "gpio"; + }; + config { + pins = "gpio68"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + hph_en1_active: hph_en1_active { + mux { + pins = "gpio68"; + function = "gpio"; + }; + config { + pins = "gpio68"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + wcd_gnd_mic_swap { wcd_gnd_mic_swap_idle: wcd_gnd_mic_swap_idle { mux { diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c index 1df839333d09..2b8d9e7080eb 100644 --- a/sound/soc/msm/msm8998.c +++ b/sound/soc/msm/msm8998.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,8 @@ #define TDM_CHANNEL_MAX 8 #define TDM_SLOT_OFFSET_MAX 8 +#define MSM_HIFI_ON 1 + enum { SLIM_RX_0 = 0, SLIM_RX_1, @@ -158,8 +161,6 @@ struct msm_wsa881x_dev_info { struct msm_asoc_mach_data { u32 mclk_freq; - int hph_en1_gpio; - int hph_en0_gpio; int us_euro_gpio; /* used by gpio driver API */ struct device_node *us_euro_gpio_p; /* used by pinctrl API */ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ @@ -415,6 +416,7 @@ static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16", static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; +static const char *const hifi_text[] = {"Off", "On"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); @@ -474,8 +476,10 @@ static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text); static struct platform_device *spdev; +static int msm_hifi_control; static bool is_initial_boot; static bool codec_reg_done; @@ -2340,6 +2344,56 @@ static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, return 1; } +static int msm_hifi_ctrl(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_card *card = codec->component.card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + pr_debug("%s: msm_hifi_control = %d", __func__, + msm_hifi_control); + + if (!pdata || !pdata->hph_en1_gpio_p) { + pr_err("%s: hph_en1_gpio is invalid\n", __func__); + return -EINVAL; + } + if (msm_hifi_control == MSM_HIFI_ON) { + msm_cdc_pinctrl_select_active_state(pdata->hph_en1_gpio_p); + /* 5msec delay needed as per HW requirement */ + usleep_range(5000, 5010); + } else { + msm_cdc_pinctrl_select_sleep_state(pdata->hph_en1_gpio_p); + } + snd_soc_dapm_sync(dapm); + + return 0; +} + +static int msm_hifi_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_hifi_control = %d\n", + __func__, msm_hifi_control); + ucontrol->value.integer.value[0] = msm_hifi_control; + + return 0; +} + +static int msm_hifi_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + + pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + msm_hifi_control = ucontrol->value.integer.value[0]; + msm_hifi_ctrl(codec); + + return 0; +} + static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs, msm_slim_rx_ch_get, msm_slim_rx_ch_put), @@ -2542,6 +2596,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs, msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get, + msm_hifi_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -2608,6 +2664,39 @@ static int msm_mclk_event(struct snd_soc_dapm_widget *w, return 0; } +static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct snd_soc_card *card = codec->component.card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + pr_debug("%s: msm_hifi_control = %d", __func__, msm_hifi_control); + + if (!pdata || !pdata->hph_en0_gpio_p) { + pr_err("%s: hph_en0_gpio is invalid\n", __func__); + return -EINVAL; + } + + if (msm_hifi_control != MSM_HIFI_ON) { + pr_debug("%s: HiFi mixer control is not set\n", + __func__); + return 0; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msm_cdc_pinctrl_select_active_state(pdata->hph_en0_gpio_p); + break; + case SND_SOC_DAPM_PRE_PMD: + msm_cdc_pinctrl_select_sleep_state(pdata->hph_en0_gpio_p); + break; + } + + return 0; +} + static const struct snd_soc_dapm_widget msm_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, @@ -2621,6 +2710,7 @@ static const struct snd_soc_dapm_widget msm_dapm_widgets[] = { SND_SOC_DAPM_SPK("Lineout_3 amp", NULL), SND_SOC_DAPM_SPK("Lineout_2 amp", NULL), SND_SOC_DAPM_SPK("Lineout_4 amp", NULL), + SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event), SND_SOC_DAPM_MIC("Handset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), @@ -3207,28 +3297,6 @@ static struct notifier_block service_nb = { .priority = -INT_MAX, }; -static int msm_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high) -{ - struct snd_soc_card *card = codec->component.card; - struct msm_asoc_mach_data *pdata; - int val; - - if (!card) - return 0; - - pdata = snd_soc_card_get_drvdata(card); - if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio)) - return 0; - - val = gpio_get_value_cansleep(pdata->hph_en0_gpio); - if ((!!val) == high) - return 0; - - gpio_direction_output(pdata->hph_en0_gpio, (int)high); - - return 1; -} - static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) { int ret = 0; @@ -5800,8 +5868,6 @@ static int msm_snd_card_late_probe(struct snd_soc_card *card) goto err_pcm_runtime; } - tasha_mbhc_zdet_gpio_ctrl(msm_config_hph_en0_gpio, rtd->codec); - mbhc_calibration = def_tasha_mbhc_cal(); if (!mbhc_calibration) { ret = -ENOMEM; @@ -5976,37 +6042,6 @@ static int msm_prepare_us_euro(struct snd_soc_card *card) return ret; } -static int msm_prepare_hifi(struct snd_soc_card *card) -{ - struct msm_asoc_mach_data *pdata = - snd_soc_card_get_drvdata(card); - int ret = 0; - - if (gpio_is_valid(pdata->hph_en1_gpio)) { - dev_dbg(card->dev, "%s: hph_en1_gpio request %d\n", __func__, - pdata->hph_en1_gpio); - ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio"); - if (ret) { - dev_err(card->dev, - "%s: hph_en1_gpio request failed, ret:%d\n", - __func__, ret); - goto err; - } - } - if (gpio_is_valid(pdata->hph_en0_gpio)) { - dev_dbg(card->dev, "%s: hph_en0_gpio request %d\n", __func__, - pdata->hph_en0_gpio); - ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio"); - if (ret) - dev_err(card->dev, - "%s: hph_en0_gpio request failed, ret:%d\n", - __func__, ret); - } - -err: - return ret; -} - static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd) { int ret = 0; @@ -6666,30 +6701,6 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) if (ret) goto err; - pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node, - "qcom,hph-en1-gpio", 0); - if (!gpio_is_valid(pdata->hph_en1_gpio)) - pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node, - "qcom,hph-en1-gpio", 0); - if (!gpio_is_valid(pdata->hph_en1_gpio) && (!pdata->hph_en1_gpio_p)) { - dev_dbg(&pdev->dev, "property %s not detected in node %s", - "qcom,hph-en1-gpio", pdev->dev.of_node->full_name); - } - - pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node, - "qcom,hph-en0-gpio", 0); - if (!gpio_is_valid(pdata->hph_en0_gpio)) - pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node, - "qcom,hph-en0-gpio", 0); - if (!gpio_is_valid(pdata->hph_en0_gpio) && (!pdata->hph_en0_gpio_p)) { - dev_dbg(&pdev->dev, "property %s not detected in node %s", - "qcom,hph-en0-gpio", pdev->dev.of_node->full_name); - } - - ret = msm_prepare_hifi(card); - if (ret) - dev_dbg(&pdev->dev, "msm_prepare_hifi failed (%d)\n", - ret); ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret == -EPROBE_DEFER) { if (codec_reg_done) @@ -6703,6 +6714,28 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Sound card %s registered\n", card->name); spdev = pdev; + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) { + dev_dbg(&pdev->dev, "%s: failed to add child nodes, ret=%d\n", + __func__, ret); + } else { + pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en1-gpio", 0); + if (!pdata->hph_en1_gpio_p) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,hph-en1-gpio", + pdev->dev.of_node->full_name); + } + + pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en0-gpio", 0); + if (!pdata->hph_en0_gpio_p) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,hph-en0-gpio", + pdev->dev.of_node->full_name); + } + } + ret = of_property_read_string(pdev->dev.of_node, "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); if (ret) { @@ -6761,18 +6794,6 @@ err: gpio_free(pdata->us_euro_gpio); pdata->us_euro_gpio = 0; } - if (pdata->hph_en1_gpio > 0) { - dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n", - __func__, pdata->hph_en1_gpio); - gpio_free(pdata->hph_en1_gpio); - pdata->hph_en1_gpio = 0; - } - if (pdata->hph_en0_gpio > 0) { - dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n", - __func__, pdata->hph_en0_gpio); - gpio_free(pdata->hph_en0_gpio); - pdata->hph_en0_gpio = 0; - } devm_kfree(&pdev->dev, pdata); return ret; } @@ -6784,8 +6805,6 @@ static int msm_asoc_machine_remove(struct platform_device *pdev) snd_soc_card_get_drvdata(card); gpio_free(pdata->us_euro_gpio); - gpio_free(pdata->hph_en1_gpio); - gpio_free(pdata->hph_en0_gpio); i2s_auxpcm_deinit(); snd_soc_unregister_card(card);