diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 22fc19dcfeb5..9ab7c9d9e72f 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -523,6 +523,9 @@ Required properties: internal or external. - qcom,msm-hs-micbias-type : This property is used to recognize the headset micbias type, internal or external. +- qcom,msm-ext-pa : This property is used to inform machine driver about + the connection of external PA over secondary MI2S interface, val 0 external + PA is not there, Val 1 external PA is connected. - qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL switch type on target typically the switch type will be normally open or normally close, value for this property 0 for normally close and 1 for @@ -559,6 +562,7 @@ Example: qcom,model = "msm8x16-snd-card"; qcom,msm-snd-card-id = <0>; qcom,msm-codec-type = "internal"; + qcom,msm-ext-pa = <0>; qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-hs-micbias-type = "internal"; diff --git a/arch/arm/boot/dts/qcom/msm8916-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8916-cdp.dtsi index eeef6663f65f..23275262585c 100644 --- a/arch/arm/boot/dts/qcom/msm8916-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-cdp.dtsi @@ -200,6 +200,7 @@ qcom,model = "msm8x16-snd-card"; qcom,msm-snd-card-id = <0>; qcom,msm-codec-type = "internal"; + qcom,msm-ext-pa = <0>; qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-hs-micbias-type = "internal"; @@ -214,9 +215,13 @@ "AMIC2", "MIC BIAS Internal2", "AMIC3", "MIC BIAS Internal3"; pinctrl-names = "cdc_pdm_lines_act", - "cdc_pdm_lines_sus"; + "cdc_pdm_lines_sus", + "cdc_ext_pa_act", + "cdc_ext_pa_sus"; pinctrl-0 = <&cdc_pdm_lines_act>; pinctrl-1 = <&cdc_pdm_lines_sus>; + pinctrl-2 = <&cdc_ext_pa_act &cdc_ext_pa_ws_act>; + pinctrl-3 = <&cdc_ext_pa_sus &cdc_ext_pa_ws_sus>; }; sound-9306 { diff --git a/arch/arm/boot/dts/qcom/msm8916-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8916-mtp.dtsi index aa6f09c0fd23..9d72fc8bd936 100644 --- a/arch/arm/boot/dts/qcom/msm8916-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-mtp.dtsi @@ -131,6 +131,7 @@ qcom,model = "msm8x16-snd-card-mtp"; qcom,msm-snd-card-id = <0>; qcom,msm-codec-type = "internal"; + qcom,msm-ext-pa = <0>; qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-hs-micbias-type = "internal"; diff --git a/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi index 23b8e3feac99..b4d16d3d8d63 100644 --- a/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi @@ -77,6 +77,38 @@ bias-disable; }; }; + + cdc-ext-pa-lines { + qcom,pins = <&gp 113>, <&gp 114>, + <&gp 115>, <&gp 116>; + qcom,num-grp-pins = <4>; + qcom,pin-func = <1>; + label = "cdc-ext-pa-lines"; + cdc_ext_pa_act: ext_pa_on { + drive-strength = <8>; + bias-pull-none; + }; + cdc_ext_pa_sus: ext_pa_off { + drive-strength = <2>; + bias-disable; + }; + }; + + cdc-ext-pa-ws-line { + qcom,pins = <&gp 110>; + qcom,num-grp-pins = <1>; + qcom,pin-func = <2>; + label = "cdc-ext-pa-ws-line"; + cdc_ext_pa_ws_act: ext_pa_on { + drive-strength = <8>; + bias-pull-none; + }; + cdc_ext_pa_ws_sus: ext_pa_off { + drive-strength = <2>; + bias-disable; + }; + }; + cross-conn-det { qcom,pins = <&gp 120>; qcom,num-grp-pins = <1>; diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h index 9595cd3537cb..5ac0ada5a7c5 100644 --- a/sound/soc/codecs/msm8x16-wcd.h +++ b/sound/soc/codecs/msm8x16-wcd.h @@ -119,6 +119,7 @@ struct msm8x16_wcd_regulator { struct msm8916_asoc_mach_data { int codec_type; + int ext_pa; int us_euro_gpio; atomic_t mclk_rsc_ref; atomic_t dis_work_mclk; diff --git a/sound/soc/msm/msm8x16.c b/sound/soc/msm/msm8x16.c index 667c0bf6ce59..007b037de12f 100644 --- a/sound/soc/msm/msm8x16.c +++ b/sound/soc/msm/msm8x16.c @@ -193,6 +193,8 @@ struct cdc_pdm_pinctrl_info { struct pinctrl_state *cdc_pdm_act; struct pinctrl_state *cross_conn_det_sus; struct pinctrl_state *cross_conn_det_act; + struct pinctrl_state *ext_pa_sus; + struct pinctrl_state *ext_pa_act; }; struct ext_cdc_tlmm_pinctrl_info { @@ -707,6 +709,54 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) } } +static int conf_int_codec_mux(struct msm8916_asoc_mach_data *pdata) +{ + int ret = 0; + int val = 0; + void __iomem *vaddr = NULL; + + /* + *configure the Primary, Sec and Tert mux for Mi2S interface + * slave select to invalid state, for machine mode this + * should move to HW, I do not like to do it here + */ + vaddr = ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL , 4); + if (!vaddr) { + pr_err("%s ioremap failure for addr %x", + __func__, LPASS_CSR_GP_IO_MUX_SPKR_CTL); + return -ENOMEM; + } + val = ioread32(vaddr); + val = val | 0x00030300; + if (pdata->ext_pa) { + /* enable sec MI2S interface to TLMM GPIO */ + val = val | 0x0004007E; + pr_debug("%s: mux configuration = %x\n", __func__, val); + ret = pinctrl_select_state(pinctrl_info.pinctrl, + pinctrl_info.ext_pa_act); + if (ret < 0) { + pr_err("%s: Failed to configure the ext pa gpio's\n", + __func__); + iounmap(vaddr); + return ret; + } + } + iowrite32(val, vaddr); + iounmap(vaddr); + vaddr = ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4); + if (!vaddr) { + pr_err("%s ioremap failure for addr %x", + __func__, LPASS_CSR_GP_IO_MUX_MIC_CTL); + return -ENOMEM; + } + val = ioread32(vaddr); + val = val | 0x00200000; + iowrite32(val, vaddr); + iounmap(vaddr); + return ret; +} + + static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -722,41 +772,10 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) substream->name, substream->stream); if (!pdata->codec_type) { - /* configure the Primary, Sec and Tert mux for Mi2S interface - * slave select to invalid state, for machine mode this - * should move to HW, I do not like to do it here - */ - vaddr = ioremap(LPASS_CSR_GP_IO_MUX_SPKR_CTL , 4); - if (!vaddr) { - pr_err("%s ioremap failure for addr %x", - __func__, LPASS_CSR_GP_IO_MUX_SPKR_CTL); - return -ENOMEM; - } - val = ioread32(vaddr); - val = val | 0x00030300; - iowrite32(val, vaddr); - iounmap(vaddr); - vaddr = ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4); - if (!vaddr) { - pr_err("%s ioremap failure for addr %x", - __func__, LPASS_CSR_GP_IO_MUX_MIC_CTL); - return -ENOMEM; - } - val = ioread32(vaddr); - iounmap(vaddr); - val = val | 0x00200000; - vaddr = ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4); - if (!vaddr) { - pr_err("%s: ioremap failure for addr %x", - __func__, LPASS_CSR_GP_IO_MUX_MIC_CTL); - return -ENOMEM; - } - iowrite32(val, vaddr); - iounmap(vaddr); - ret = msm8x16_enable_codec_ext_clk(codec, 1, true); + ret = conf_int_codec_mux(pdata); if (ret < 0) { - pr_err("%s: failed to enable mclk; ret=%d\n", - __func__, ret); + pr_err("%s: failed to conf internal codec mux\n", + __func__); return ret; } ret = mi2s_clk_ctl(substream, true); @@ -765,6 +784,11 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) __func__, ret); return ret; } + ret = msm8x16_enable_codec_ext_clk(codec, 1, true); + if (ret < 0) { + pr_err("failed to enable mclk\n"); + return ret; + } /* Reset the CDC PDM TLMM pins to a default state */ ret = pinctrl_select_state(pinctrl_info.pinctrl, pinctrl_info.cdc_pdm_act); @@ -788,7 +812,6 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) val = val | 0x00000002; iowrite32(val, vaddr); iounmap(vaddr); - vaddr = ioremap(LPASS_CSR_GP_IO_MUX_MIC_CTL , 4); if (!vaddr) { pr_err("%s: ioremap failure for addr %x", @@ -1774,9 +1797,11 @@ static int msm8x16_asoc_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct msm8916_asoc_mach_data *pdata = NULL; + struct pinctrl *pinctrl; const char *card_dev_id = "qcom,msm-snd-card-id"; const char *codec_type = "qcom,msm-codec-type"; const char *hs_micbias_type = "qcom,msm-hs-micbias-type"; + const char *ext_pa = "qcom,msm-ext-pa"; const char *ptr = NULL; const char *type = NULL; int ret, id; @@ -1843,6 +1868,39 @@ static int msm8x16_asoc_machine_probe(struct platform_device *pdev) card = &bear_cards[pdev->id]; dev_info(&pdev->dev, "default codec configured\n"); pdata->codec_type = 0; + ret = of_property_read_u32(pdev->dev.of_node, ext_pa, &id); + if (ret) { + dev_err(&pdev->dev, + "%s: missing %s in dt node\n", + __func__, ext_pa); + goto err; + } + pdata->ext_pa = id; + if (pdata->ext_pa) { + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(pinctrl)) { + pr_err("%s: Unable to get pinctrl handle\n", + __func__); + return -EINVAL; + } + pinctrl_info.pinctrl = pinctrl; + /* get pinctrl handle for ext_pa */ + pinctrl_info.ext_pa_sus = pinctrl_lookup_state(pinctrl, + "cdc_ext_pa_sus"); + if (IS_ERR(pinctrl_info.ext_pa_sus)) { + pr_err("%s: Unable to get pinctrl disable handle\n", + __func__); + return -EINVAL; + } + /* get pinctrl handle for ext_pa */ + pinctrl_info.ext_pa_act = pinctrl_lookup_state(pinctrl, + "cdc_ext_pa_act"); + if (IS_ERR(pinctrl_info.ext_pa_act)) { + pr_err("%s: Unable to get pinctrl disable handle\n", + __func__); + return -EINVAL; + } + } } ret = of_property_read_string(pdev->dev.of_node,