From 10f9ebb4d4a85e74266cb111f10c7b4cca1c78ed Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Fri, 4 Nov 2016 23:27:20 +0530 Subject: [PATCH 1/2] ARM: dts: msm: Add pinctrl device nodes for HiFi amplifier on MSM8998 HiFi amplifier uses lineout path in the codec to be routed to headphone amplifiers. This routing needs two gpios to be toggled. Add pinctrl device nodes to control gpios for HiFi amplifier usecase. Change-Id: I8d34eecd562ab50a8ec89f241406092d1b763a9a Signed-off-by: Sudheer Papothi --- arch/arm/boot/dts/qcom/msm8998-audio.dtsi | 20 ++++++++ arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi | 54 +++++++++++++++++++++ 2 files changed, 74 insertions(+) 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 5685e9041fe4..b48321a5ee10 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 { From e36bea71e294a196f791258fb61d7ea727c0a2e3 Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Thu, 20 Oct 2016 22:41:06 +0530 Subject: [PATCH 2/2] ASoC: msm8998: Add support for HiFi amplifier HiFi amplifier uses lineout path and routed to headphones. This is used for better quality of audio on headphones. Add support to enable HiFi amplifier on msm8998. Change-Id: I3f2cadbb74b3a68d91938f20afff2ab0ab42b4bd Signed-off-by: Sudheer Papothi --- sound/soc/msm/msm8998.c | 209 ++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 95 deletions(-) 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);