高通msm8909耳麦调节和测试

http://blog.csdn.net/mike8825/article/details/69489865?locationnum=3&fps=1

http://blog.csdn.net/mike8825/article/details/69489865?locationnum=3&fps=1

 

 

 

 

壹 、DTS相应修改:

DTS相关代码:kernel/arch/arm/boot/dts/qcom/msm8909-qrd-skuc.dtsi:

 1     sound {
 2         compatible = "qcom,msm8x16-audio-codec";
 3         qcom,model = "msm8909-skuc-snd-card";
 4         qcom,msm-snd-card-id = <0>;
 5         qcom,msm-codec-type = "internal";
 6         qcom,msm-ext-pa = "primary";
 7         qcom,msm-mclk-freq = <9600000>;
 8         qcom,msm-mbhc-hphl-swh = <0>;        //高通平台耳机驱动机制为MBHC,hphl为
 9         qcom,msm-mbhc-gnd-swh = <0>;
10         qcom,msm-hs-micbias-type = "internal";
11         qcom,msm-micbias1-ext-cap;
12         qcom,msm-micbias2-ext-cap;
13         qcom,audio-routing =
14             "RX_BIAS", "MCLK",
15             "SPK_RX_BIAS", "MCLK",
16             "INT_LDO_H", "MCLK",
17             "MIC BIAS Internal1", "Handset Mic",
18             "MIC BIAS Internal2", "Headset Mic",
19             "MIC BIAS Internal3", "Secondary Mic",
20             "AMIC1", "MIC BIAS Internal1",
21             "AMIC2", "MIC BIAS Internal2",
22             "AMIC3", "MIC BIAS Internal3";
23         pinctrl-names = "cdc_lines_act",
24                 "cdc_lines_sus";
25         pinctrl-0 = <&cdc_pdm_lines_act>;
26         pinctrl-1 = <&cdc_pdm_lines_sus>;
27         asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
28                 <&loopback>, <&compress>, <&hostless>,
29                 <&afe>, <&lsm>, <&routing>, <&lpa>,
30                 <&voice_svc>;
31         asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
32                 "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
33                 "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
34                 "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa",
35                 "msm-voice-svc";
36         asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>,
37                 <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>,
38                 <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
39                 <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
40                 <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
41                 <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
42                 <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
43                 <&incall_music_2_rx>;
44         asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8",
45                 "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
46                 "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
47                 "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
48                 "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
49                 "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
50                 "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
51                 "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
52                 "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
53                 "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
54                 "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
55                 "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
56                 "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
57         asoc-codec = <&stub_codec>, <&pm8909_conga_dig>;      //在这里使用了pm8909电源管理芯片的codec芯片
58         asoc-codec-names = "msm-stub-codec.1", "tombak_codec";
59     };

 

通过find ./ -name “*8909*” | xargs grep -n
“pm8909_conga_dig”来搜寻关键字:

图片 1

 

kernel/arch/arm/boot/dts/qcom/msm-pm8909.dtsi:

    pm8909_conga_dig: 8909_wcd_codec@f000 {
            compatible = "qcom,msm8x16_wcd_codec";
            reg = <0xf000 0x100>;
            interrupt-parent = <&spmi_bus>;
            interrupts = <0x1 0xf0 0x0>,
                     <0x1 0xf0 0x1>,
                     <0x1 0xf0 0x2>,
                     <0x1 0xf0 0x3>,
                     <0x1 0xf0 0x4>,
                     <0x1 0xf0 0x5>,
                     <0x1 0xf0 0x6>,
                     <0x1 0xf0 0x7>;
            interrupt-names = "spk_cnp_int",
                      "spk_clip_int",
                      "spk_ocp_int",
                      "ins_rem_det1",
                      "but_rel_det",
                      "but_press_det",
                      "ins_rem_det",
                      "mbhc_int";

            cdc-vdda-cp-supply = <&pm8909_s2>;
            qcom,cdc-vdda-cp-voltage = <1800000 2200000>;
            qcom,cdc-vdda-cp-current = <500000>;

            cdc-vdda-h-supply = <&pm8909_l5>;
            qcom,cdc-vdda-h-voltage = <1800000 1800000>;
            qcom,cdc-vdda-h-current = <10000>;

            cdc-vdd-px-supply = <&pm8909_l5>;
            qcom,cdc-vdd-px-voltage = <1800000 1800000>;
            qcom,cdc-vdd-px-current = <5000>;

            cdc-vdd-pa-supply = <&pm8909_s2>;
            qcom,cdc-vdd-pa-voltage = <1800000 2200000>;
            qcom,cdc-vdd-pa-current = <260000>;

            cdc-vdd-mic-bias-supply = <&pm8909_l13>;
            qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
            qcom,cdc-vdd-mic-bias-current = <5000>;

            qcom,cdc-mclk-clk-rate = <9600000>;

            qcom,cdc-static-supplies = "cdc-vdda-h",
                           "cdc-vdd-px",
                           "cdc-vdd-pa",
                           "cdc-vdda-cp";

            qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
        };

        pm8909_conga_analog: 8909_wcd_codec@f100 {
            compatible = "qcom,msm8x16_wcd_codec";
            reg = <0xf100 0x100>;
            interrupt-parent = <&spmi_bus>;
            interrupts = <0x1 0xf1 0x0>,
                     <0x1 0xf1 0x1>,
                     <0x1 0xf1 0x2>,
                     <0x1 0xf1 0x3>,
                     <0x1 0xf1 0x4>,
                     <0x1 0xf1 0x5>;
            interrupt-names = "ear_ocp_int",
                      "hphr_ocp_int",
                      "hphl_ocp_det",
                      "ear_cnp_int",
                      "hphr_cnp_int",
                      "hphl_cnp_int";
        };

 

 

msm8909的动圈耳机接口在pm8909上,耳计算机检索查和测试脚是HS_DET。

明确自个儿的插座是NO依然NC的,详情查看博客:http://www.cnblogs.com/linhaostudy/p/8260813.html

通过检查,判断JACK为NO状态;依据MTKbring
up 手册更改相应的DTSI:

图片 2

1 qcom,msm-mbhc-hphl-swh = <1>;    //由0改为1

 

 

 

 

壹 、DTS相应修改:

DTS相关代码:kernel/arch/arm/boot/dts/qcom/msm8909-qrd-skuc.dtsi:

 1     sound {
 2         compatible = "qcom,msm8x16-audio-codec";
 3         qcom,model = "msm8909-skuc-snd-card";
 4         qcom,msm-snd-card-id = <0>;
 5         qcom,msm-codec-type = "internal";
 6         qcom,msm-ext-pa = "primary";
 7         qcom,msm-mclk-freq = <9600000>;
 8         qcom,msm-mbhc-hphl-swh = <0>;        //高通平台耳机驱动机制为MBHC,hphl为
 9         qcom,msm-mbhc-gnd-swh = <0>;
10         qcom,msm-hs-micbias-type = "internal";
11         qcom,msm-micbias1-ext-cap;
12         qcom,msm-micbias2-ext-cap;
13         qcom,audio-routing =
14             "RX_BIAS", "MCLK",
15             "SPK_RX_BIAS", "MCLK",
16             "INT_LDO_H", "MCLK",
17             "MIC BIAS Internal1", "Handset Mic",
18             "MIC BIAS Internal2", "Headset Mic",
19             "MIC BIAS Internal3", "Secondary Mic",
20             "AMIC1", "MIC BIAS Internal1",
21             "AMIC2", "MIC BIAS Internal2",
22             "AMIC3", "MIC BIAS Internal3";
23         pinctrl-names = "cdc_lines_act",
24                 "cdc_lines_sus";
25         pinctrl-0 = <&cdc_pdm_lines_act>;
26         pinctrl-1 = <&cdc_pdm_lines_sus>;
27         asoc-platform = <&pcm0>, <&pcm1>, <&voip>, <&voice>,
28                 <&loopback>, <&compress>, <&hostless>,
29                 <&afe>, <&lsm>, <&routing>, <&lpa>,
30                 <&voice_svc>;
31         asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
32                 "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback",
33                 "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe",
34                 "msm-lsm-client", "msm-pcm-routing", "msm-pcm-lpa",
35                 "msm-voice-svc";
36         asoc-cpu = <&dai_pri_auxpcm>, <&dai_hdmi>,
37                 <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>,
38                 <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
39                 <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
40                 <&bt_sco_rx>, <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
41                 <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, <&afe_proxy_tx>,
42                 <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>,
43                 <&incall_music_2_rx>;
44         asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-hdmi.8",
45                 "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
46                 "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
47                 "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
48                 "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
49                 "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
50                 "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
51                 "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
52                 "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
53                 "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
54                 "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
55                 "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
56                 "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
57         asoc-codec = <&stub_codec>, <&pm8909_conga_dig>;      //在这里使用了pm8909电源管理芯片的codec芯片
58         asoc-codec-names = "msm-stub-codec.1", "tombak_codec";
59     };

 

通过find ./ -name “*8909*” | xargs grep -n
“pm8909_conga_dig”来探寻关键字:

图片 3

 

kernel/arch/arm/boot/dts/qcom/msm-pm8909.dtsi:

    pm8909_conga_dig: 8909_wcd_codec@f000 {
            compatible = "qcom,msm8x16_wcd_codec";
            reg = <0xf000 0x100>;
            interrupt-parent = <&spmi_bus>;
            interrupts = <0x1 0xf0 0x0>,
                     <0x1 0xf0 0x1>,
                     <0x1 0xf0 0x2>,
                     <0x1 0xf0 0x3>,
                     <0x1 0xf0 0x4>,
                     <0x1 0xf0 0x5>,
                     <0x1 0xf0 0x6>,
                     <0x1 0xf0 0x7>;
            interrupt-names = "spk_cnp_int",
                      "spk_clip_int",
                      "spk_ocp_int",
                      "ins_rem_det1",
                      "but_rel_det",
                      "but_press_det",
                      "ins_rem_det",
                      "mbhc_int";

            cdc-vdda-cp-supply = <&pm8909_s2>;
            qcom,cdc-vdda-cp-voltage = <1800000 2200000>;
            qcom,cdc-vdda-cp-current = <500000>;

            cdc-vdda-h-supply = <&pm8909_l5>;
            qcom,cdc-vdda-h-voltage = <1800000 1800000>;
            qcom,cdc-vdda-h-current = <10000>;

            cdc-vdd-px-supply = <&pm8909_l5>;
            qcom,cdc-vdd-px-voltage = <1800000 1800000>;
            qcom,cdc-vdd-px-current = <5000>;

            cdc-vdd-pa-supply = <&pm8909_s2>;
            qcom,cdc-vdd-pa-voltage = <1800000 2200000>;
            qcom,cdc-vdd-pa-current = <260000>;

            cdc-vdd-mic-bias-supply = <&pm8909_l13>;
            qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
            qcom,cdc-vdd-mic-bias-current = <5000>;

            qcom,cdc-mclk-clk-rate = <9600000>;

            qcom,cdc-static-supplies = "cdc-vdda-h",
                           "cdc-vdd-px",
                           "cdc-vdd-pa",
                           "cdc-vdda-cp";

            qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
        };

        pm8909_conga_analog: 8909_wcd_codec@f100 {
            compatible = "qcom,msm8x16_wcd_codec";
            reg = <0xf100 0x100>;
            interrupt-parent = <&spmi_bus>;
            interrupts = <0x1 0xf1 0x0>,
                     <0x1 0xf1 0x1>,
                     <0x1 0xf1 0x2>,
                     <0x1 0xf1 0x3>,
                     <0x1 0xf1 0x4>,
                     <0x1 0xf1 0x5>;
            interrupt-names = "ear_ocp_int",
                      "hphr_ocp_int",
                      "hphl_ocp_det",
                      "ear_cnp_int",
                      "hphr_cnp_int",
                      "hphl_cnp_int";
        };

 

 

msm8909的动铁耳机接口在pm8909上,耳计算机检索查和测试脚是HS_DET。

鲜明自个儿的插座是NO照旧NC的,详情查看博客:http://www.cnblogs.com/linhaostudy/p/8260813.html

通过反省,判断JACK为NO状态;依据MediaTekbring
up 手册更改相应的DTSI:

图片 4

1 qcom,msm-mbhc-hphl-swh = <1>;    //由0改为1

 

 

 

 

2、kernel分析:

kernel/sound/soc/codecs/msm8x16-wcd.c

1 static const struct wcd_mbhc_intr intr_ids = {
2     .mbhc_sw_intr =  MSM8X16_WCD_IRQ_MBHC_HS_DET,
3     .mbhc_btn_press_intr = MSM8X16_WCD_IRQ_MBHC_PRESS,
4     .mbhc_btn_release_intr = MSM8X16_WCD_IRQ_MBHC_RELEASE,
5     .mbhc_hs_ins_intr = MSM8X16_WCD_IRQ_MBHC_INSREM_DET1,
6     .mbhc_hs_rem_intr = MSM8X16_WCD_IRQ_MBHC_INSREM_DET,
7     .hph_left_ocp = MSM8X16_WCD_IRQ_HPHL_OCP,
8     .hph_right_ocp = MSM8X16_WCD_IRQ_HPHR_OCP,
9 };

  那么些结构体描述了msm8909的wcdx类别的codec芯片的MBHC的音信;

 

 

  1 static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
  2 {
  3     struct msm8x16_wcd_priv *msm8x16_wcd_priv;
  4     struct msm8x16_wcd *msm8x16_wcd;
  5     int i, ret;
  6 
  7     dev_dbg(codec->dev, "%s()\n", __func__);
  8 
  9     msm8x16_wcd_priv = kzalloc(sizeof(struct msm8x16_wcd_priv), GFP_KERNEL);
 10     if (!msm8x16_wcd_priv) {
 11         dev_err(codec->dev, "Failed to allocate private data\n");
 12         return -ENOMEM;
 13     }
 14 
 15     for (i = 0; i < NUM_DECIMATORS; i++) {
 16         tx_hpf_work[i].msm8x16_wcd = msm8x16_wcd_priv;
 17         tx_hpf_work[i].decimator = i + 1;
 18         INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
 19             tx_hpf_corner_freq_callback);
 20     }
 21 
 22     codec->control_data = dev_get_drvdata(codec->dev);
 23     snd_soc_codec_set_drvdata(codec, msm8x16_wcd_priv);
 24     msm8x16_wcd_priv->codec = codec;
 25 
 26     /* codec resmgr module init */
 27     msm8x16_wcd = codec->control_data;
 28     msm8x16_wcd->dig_base = ioremap(MSM8X16_DIGITAL_CODEC_BASE_ADDR,
 29                   MSM8X16_DIGITAL_CODEC_REG_SIZE);
 30     if (msm8x16_wcd->dig_base == NULL) {
 31         dev_err(codec->dev, "%s ioremap failed\n", __func__);
 32         kfree(msm8x16_wcd_priv);
 33         return -ENOMEM;
 34     }
 35     msm8x16_wcd_priv->spkdrv_reg =
 36         wcd8x16_wcd_codec_find_regulator(codec->control_data,
 37                         MSM89XX_VDD_SPKDRV_NAME);
 38     msm8x16_wcd_priv->pmic_rev = snd_soc_read(codec,
 39                     MSM8X16_WCD_A_DIGITAL_REVISION1);
 40     msm8x16_wcd_priv->codec_version = snd_soc_read(codec,
 41                     MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE);
 42     if (msm8x16_wcd_priv->codec_version == CONGA) {
 43         dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__,
 44                     msm8x16_wcd_priv->codec_version);
 45         msm8x16_wcd_priv->ext_spk_boost_set = true;
 46     } else {
 47         dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__,
 48                     msm8x16_wcd_priv->pmic_rev);
 49     }
 50     /*
 51      * set to default boost option BOOST_SWITCH, user mixer path can change
 52      * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
 53      */
 54     msm8x16_wcd_priv->boost_option = BOOST_SWITCH;
 55     msm8x16_wcd_dt_parse_boost_info(codec);    //
 56     msm8x16_wcd_set_boost_v(codec);
 57 
 58     snd_soc_add_codec_controls(codec, impedance_detect_controls,
 59                    ARRAY_SIZE(impedance_detect_controls));
 60 
 61     msm8x16_wcd_bringup(codec);
 62     msm8x16_wcd_codec_init_reg(codec);
 63     msm8x16_wcd_update_reg_defaults(codec);
 64 
 65     wcd9xxx_spmi_set_codec(codec);
 66 
 67     msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
 68                 wcd8x16_wcd_codec_find_regulator(
 69                 codec->control_data,
 70                 on_demand_supply_name[ON_DEMAND_MICBIAS]);
 71     atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
 72 
 73     BLOCKING_INIT_NOTIFIER_HEAD(&msm8x16_wcd_priv->notifier);
 74 
 75     msm8x16_wcd_priv->fw_data = kzalloc(sizeof(*(msm8x16_wcd_priv->fw_data))
 76             , GFP_KERNEL);
 77     if (!msm8x16_wcd_priv->fw_data) {
 78         dev_err(codec->dev, "Failed to allocate fw_data\n");
 79         iounmap(msm8x16_wcd->dig_base);
 80         kfree(msm8x16_wcd_priv);
 81         return -ENOMEM;
 82     }
 83 
 84     set_bit(WCD9XXX_MBHC_CAL, msm8x16_wcd_priv->fw_data->cal_bit);
 85     ret = wcd_cal_create_hwdep(msm8x16_wcd_priv->fw_data,
 86             WCD9XXX_CODEC_HWDEP_NODE, codec);
 87     if (ret < 0) {
 88         dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
 89         iounmap(msm8x16_wcd->dig_base);
 90         kfree(msm8x16_wcd_priv->fw_data);
 91         kfree(msm8x16_wcd_priv);
 92         return ret;
 93     }
 94 
 95     wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
 96             true);        //在这里获取到了相应的设备树信息
 97 
 98     msm8x16_wcd_priv->mclk_enabled = false;
 99     msm8x16_wcd_priv->clock_active = false;
100     msm8x16_wcd_priv->config_mode_active = false;
101 
102     /* Set initial MICBIAS voltage level */
103     msm8x16_wcd_set_micb_v(codec);
104 
105     /* Set initial cap mode */
106     msm8x16_wcd_configure_cap(codec, false, false);
107     registered_codec = codec;
108     modem_state_notifier =
109         subsys_notif_register_notifier("modem",
110                        &modem_state_notifier_block);
111     if (!modem_state_notifier) {
112         dev_err(codec->dev, "Failed to register modem state notifier\n"
113             );
114         iounmap(msm8x16_wcd->dig_base);
115         kfree(msm8x16_wcd_priv->fw_data);
116         kfree(msm8x16_wcd_priv);
117         registered_codec = NULL;
118         return -ENOMEM;
119     }
120     return 0;
121 }

 

kernel/sound/soc/codecs/wcd-mbhc-v2.c:

  1 int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
  2               const struct wcd_mbhc_cb *mbhc_cb,
  3               const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
  4               bool impedance_det_en)
  5 {
  6     int ret = 0;
  7     int hph_swh = 0;
  8     int gnd_swh = 0;
  9     struct snd_soc_card *card = codec->card;
 10     const char *hph_switch = "qcom,msm-mbhc-hphl-swh";
 11     const char *gnd_switch = "qcom,msm-mbhc-gnd-swh";
 12     const char *ext1_cap = "qcom,msm-micbias1-ext-cap";
 13     const char *ext2_cap = "qcom,msm-micbias2-ext-cap";
 14 
 15     pr_debug("%s: enter\n", __func__);
 16 
 17     ret = of_property_read_u32(card->dev->of_node, hph_switch, &hph_swh);    //在这里找到设备树信息,通过高低电平判断no或者nc的jack
 18     if (ret) {
 19         dev_err(card->dev,
 20             "%s: missing %s in dt node\n", __func__, hph_switch);
 21         goto err;
 22     }
 23 
 24     ret = of_property_read_u32(card->dev->of_node, gnd_switch, &gnd_swh);
 25     if (ret) {
 26         dev_err(card->dev,
 27             "%s: missing %s in dt node\n", __func__, gnd_switch);
 28         goto err;
 29     }
 30     mbhc->micbias1_cap_mode =
 31         (of_property_read_bool(card->dev->of_node, ext1_cap) ?
 32         MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
 33 
 34     mbhc->micbias2_cap_mode =
 35         (of_property_read_bool(card->dev->of_node, ext2_cap) ?
 36         MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
 37 
 38     mbhc->in_swch_irq_handler = false;
 39     mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
 40     mbhc->is_btn_press = false;
 41     mbhc->codec = codec;
 42     mbhc->intr_ids = mbhc_cdc_intr_ids;
 43     mbhc->impedance_detect = impedance_det_en;
 44     mbhc->hphl_swh = hph_swh;
 45     mbhc->gnd_swh = gnd_swh;
 46     mbhc->micbias_enable = false;
 47     mbhc->mbhc_cb = mbhc_cb;
 48     mbhc->btn_press_intr = false;
 49 
 50     if (mbhc->intr_ids == NULL) {
 51         pr_err("%s: Interrupt mapping not provided\n", __func__);
 52         return -EINVAL;
 53     }
 54 
 55     if (mbhc->headset_jack.jack == NULL) {
 56         ret = snd_soc_jack_new(codec, "Headset Jack",
 57                 WCD_MBHC_JACK_MASK, &mbhc->headset_jack);
 58         if (ret) {
 59             pr_err("%s: Failed to create new jack\n", __func__);
 60             return ret;
 61         }
 62 
 63         ret = snd_soc_jack_new(codec, "Button Jack",
 64                        WCD_MBHC_JACK_BUTTON_MASK,
 65                        &mbhc->button_jack);
 66         if (ret) {
 67             pr_err("Failed to create new jack\n");
 68             return ret;
 69         }
 70 
 71         ret = snd_jack_set_key(mbhc->button_jack.jack,
 72                        SND_JACK_BTN_0,
 73                        KEY_MEDIA);
 74         if (ret) {
 75             pr_err("%s: Failed to set code for btn-0\n",
 76                 __func__);
 77             return ret;
 78         }
 79 
 80         INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_lpress_fn);
 81     }
 82 
 83     /* Register event notifier */
 84     mbhc->nblock.notifier_call = wcd_event_notify;
 85     ret = msm8x16_register_notifier(codec, &mbhc->nblock);
 86     if (ret) {
 87         pr_err("%s: Failed to register notifier %d\n", __func__, ret);
 88         return ret;
 89     }
 90 
 91     init_waitqueue_head(&mbhc->wait_btn_press);
 92     mutex_init(&mbhc->codec_resource_lock);
 93 
 94     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_sw_intr,
 95                   wcd_mbhc_mech_plug_detect_irq,
 96                   "mbhc sw intr", mbhc);
 97     if (ret) {
 98         pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
 99                mbhc->intr_ids->mbhc_sw_intr, ret);
100         goto err_mbhc_sw_irq;
101     }
102 
103     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_btn_press_intr,
104                   wcd_mbhc_btn_press_handler,
105                   "Button Press detect",
106                   mbhc);
107     if (ret) {
108         pr_err("%s: Failed to request irq %d\n", __func__,
109                mbhc->intr_ids->mbhc_btn_press_intr);
110         goto err_btn_press_irq;
111     }
112 
113     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_btn_release_intr,
114                   wcd_mbhc_release_handler,
115                   "Button Release detect", mbhc);
116     if (ret) {
117         pr_err("%s: Failed to request irq %d\n", __func__,
118             mbhc->intr_ids->mbhc_btn_release_intr);
119         goto err_btn_release_irq;
120     }
121 
122     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_hs_ins_intr,
123                   wcd_mbhc_hs_ins_irq,
124                   "Elect Insert", mbhc);
125     if (ret) {
126         pr_err("%s: Failed to request irq %d\n", __func__,
127                mbhc->intr_ids->mbhc_hs_ins_intr);
128         goto err_mbhc_hs_ins_irq;
129     }
130     wcd9xxx_spmi_disable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
131 
132     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_hs_rem_intr,
133                   wcd_mbhc_hs_rem_irq,
134                   "Elect Remove", mbhc);
135     if (ret) {
136         pr_err("%s: Failed to request irq %d\n", __func__,
137                mbhc->intr_ids->mbhc_hs_rem_intr);
138         goto err_mbhc_hs_rem_irq;
139     }
140     wcd9xxx_spmi_disable_irq(mbhc->intr_ids->mbhc_hs_rem_intr);
141 
142     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->hph_left_ocp,
143                   wcd_mbhc_hphl_ocp_irq, "HPH_L OCP detect",
144                   mbhc);                          //在这里申请对detect管脚的判断中断
145     if (ret) {
146         pr_err("%s: Failed to request irq %d\n", __func__,
147                mbhc->intr_ids->hph_left_ocp);
148         goto err_hphl_ocp_irq;
149     }
150 
151     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->hph_right_ocp,
152                   wcd_mbhc_hphr_ocp_irq, "HPH_R OCP detect",
153                   mbhc);
154     if (ret) {
155         pr_err("%s: Failed to request irq %d\n", __func__,
156                mbhc->intr_ids->hph_right_ocp);
157         goto err_hphr_ocp_irq;
158     }
159 
160     pr_debug("%s: leave ret %d\n", __func__, ret);
161     return ret;
162 
163 err_hphr_ocp_irq:
164     wcd9xxx_spmi_free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
165 err_hphl_ocp_irq:
166     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
167 err_mbhc_hs_rem_irq:
168     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
169 err_mbhc_hs_ins_irq:
170     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
171 err_btn_release_irq:
172     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
173 err_btn_press_irq:
174     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
175 err_mbhc_sw_irq:
176     msm8x16_unregister_notifier(codec, &mbhc->nblock);
177     mutex_destroy(&mbhc->codec_resource_lock);
178 err:
179     pr_debug("%s: leave ret %d\n", __func__, ret);
180     return ret;
181 }

 1 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
 2 {
 3     int r = IRQ_HANDLED;
 4     struct wcd_mbhc *mbhc = data;
 5 
 6     pr_debug("%s: enter\n", __func__);
 7     if (unlikely(wcd9xxx_spmi_lock_sleep() == false)) {
 8         pr_warn("%s: failed to hold suspend\n", __func__);
 9         r = IRQ_NONE;
10     } else {
11         /* Call handler */
12         wcd_mbhc_swch_irq_handler(mbhc);        //中断函数中的接口,负责处理相应的
13         wcd9xxx_spmi_unlock_sleep();
14     }
15     pr_debug("%s: leave %d\n", __func__, r);
16     return r;
17 }

  1 static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
  2 {
  3     bool detection_type;
  4     bool micbias1;
  5     struct snd_soc_codec *codec = mbhc->codec;
  6     pr_debug("%s: enter\n", __func__);
  7 
  8     WCD_MBHC_RSC_LOCK(mbhc);
  9 
 10     mbhc->in_swch_irq_handler = true;
 11 
 12     /* cancel pending button press */
 13     if (wcd_cancel_btn_work(mbhc))
 14         pr_debug("%s: button press is canceled\n", __func__);
 15 
 16     detection_type = (snd_soc_read(codec,
 17                 MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1)) & 0x20;
 18 
 19     /* Set the detection type appropriately */
 20     snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
 21             0x20, (!detection_type << 5));
 22 
 23     pr_debug("%s: mbhc->current_plug: %d detection_type: %d\n", __func__,
 24             mbhc->current_plug, detection_type);
 25     wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
 26 
 27     micbias1 = (snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN) & 0x80);
 28     if ((mbhc->current_plug == MBHC_PLUG_TYPE_NONE) &&
 29         detection_type) {
 30         /* Make sure MASTER_BIAS_CTL is enabled */
 31         snd_soc_update_bits(codec,
 32                     MSM8X16_WCD_A_ANALOG_MASTER_BIAS_CTL,
 33                     0x30, 0x30);
 34         snd_soc_update_bits(codec,
 35                 MSM8X16_WCD_A_ANALOG_MICB_1_EN,
 36                 0x04, 0x04);
 37         if (!mbhc->mbhc_cfg->hs_ext_micbias)
 38             /* Enable Tx2 RBias if the headset
 39              * is using internal micbias*/
 40             snd_soc_update_bits(codec,
 41                     MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS,
 42                     0x10, 0x10);
 43         /* Remove pull down on MIC BIAS2 */
 44         snd_soc_update_bits(codec,
 45                  MSM8X16_WCD_A_ANALOG_MICB_2_EN,
 46                 0x20, 0x00);
 47         /* Enable HW FSM */
 48         snd_soc_update_bits(codec,
 49                 MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
 50                 0x80, 0x80);
 51         /* Apply trim if needed on the device */
 52         if (mbhc->mbhc_cb && mbhc->mbhc_cb->trim_btn_reg)
 53             mbhc->mbhc_cb->trim_btn_reg(codec);
 54         /* Enable external voltage source to micbias if present */
 55         if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
 56             mbhc->mbhc_cb->enable_mb_source(codec, true);
 57         mbhc->btn_press_intr = false;
 58         wcd_mbhc_detect_plug_type(mbhc);
 59     } else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
 60             && !detection_type) {
 61         /* Disable external voltage source to micbias if present */
 62         if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
 63             mbhc->mbhc_cb->enable_mb_source(codec, false);
 64         /* Disable HW FSM */
 65         snd_soc_update_bits(codec,
 66                 MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
 67                 0xB0, 0x00);
 68         snd_soc_update_bits(codec,
 69                 MSM8X16_WCD_A_ANALOG_MICB_1_EN,
 70                 0x04, 0x00);
 71         if (mbhc->mbhc_cb && mbhc->mbhc_cb->set_cap_mode)
 72             mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
 73         mbhc->btn_press_intr = false;
 74         if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {        //如果判断是headphone,上报数据;
 75             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
 76         } else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
 77             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
 78         } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
 79             /* make sure to turn off Rbias */
 80             snd_soc_update_bits(codec,
 81                     MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS,
 82                     0x18, 0x08);
 83             snd_soc_update_bits(codec,
 84                     MSM8X16_WCD_A_ANALOG_MICB_2_EN,
 85                     0x20, 0x20);
 86             wcd9xxx_spmi_disable_irq(
 87                     mbhc->intr_ids->mbhc_hs_rem_intr);
 88             wcd9xxx_spmi_disable_irq(
 89                     mbhc->intr_ids->mbhc_hs_ins_intr);
 90             snd_soc_update_bits(codec,
 91                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
 92                     0x01, 0x01);
 93             snd_soc_update_bits(codec,
 94                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
 95                     0x06, 0x00);
 96             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
 97         } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) {
 98             mbhc->is_extn_cable = false;
 99             wcd9xxx_spmi_disable_irq(
100                     mbhc->intr_ids->mbhc_hs_rem_intr);
101             wcd9xxx_spmi_disable_irq(
102                     mbhc->intr_ids->mbhc_hs_ins_intr);
103             snd_soc_update_bits(codec,
104                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
105                     0x01, 0x01);
106             snd_soc_update_bits(codec,
107                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
108                     0x06, 0x00);
109             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
110         }
111     } else if (!detection_type) {
112         /* Disable external voltage source to micbias if present */
113         if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
114             mbhc->mbhc_cb->enable_mb_source(codec, false);
115         /* Disable HW FSM */
116         snd_soc_update_bits(codec,
117                 MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
118                 0xB0, 0x00);
119     }
120 
121     mbhc->in_swch_irq_handler = false;
122     WCD_MBHC_RSC_UNLOCK(mbhc);
123     pr_debug("%s: leave\n", __func__);
124 }

 

透过一多如牛毛的检测,判断是headset,headphones等,若是是headphones,最后通过wcd_mbhc_jack_report将数据反映上去。

 

图片 5图片 6

  1 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
  2                 enum snd_jack_types jack_type)
  3 {
  4     struct snd_soc_codec *codec = mbhc->codec;
  5     WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
  6 
  7     pr_debug("%s: enter insertion %d hph_status %x\n",
  8          __func__, insertion, mbhc->hph_status);
  9     if (!insertion) {
 10         /* Report removal */
 11         mbhc->hph_status &= ~jack_type;
 12         /*
 13          * cancel possibly scheduled btn work and
 14          * report release if we reported button press
 15          */
 16         if (wcd_cancel_btn_work(mbhc)) {
 17             pr_debug("%s: button press is canceled\n", __func__);
 18         } else if (mbhc->buttons_pressed) {
 19             pr_debug("%s: release of button press%d\n",
 20                  __func__, jack_type);
 21             wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, 0,
 22                         mbhc->buttons_pressed);
 23             mbhc->buttons_pressed &=
 24                 ~WCD_MBHC_JACK_BUTTON_MASK;
 25         }
 26 
 27         if (mbhc->micbias_enable)
 28             mbhc->micbias_enable = false;
 29 
 30         mbhc->zl = mbhc->zr = 0;
 31         mbhc->is_hs_inserted = false;
 32         pr_debug("%s: Reporting removal %d(%x)\n", __func__,
 33              jack_type, mbhc->hph_status);
 34         wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
 35                 mbhc->hph_status, WCD_MBHC_JACK_MASK);
 36         wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
 37         hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
 38         hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
 39         mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
 40     } else {
 41         /*
 42          * Report removal of current jack type.
 43          * Headphone to headset shouldn't report headphone
 44          * removal.
 45          */
 46         if (mbhc->mbhc_cfg->detect_extn_cable &&
 47             (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH ||
 48             jack_type == SND_JACK_LINEOUT) &&
 49             (mbhc->hph_status && mbhc->hph_status != jack_type)) {
 50 
 51         if (mbhc->micbias_enable)
 52             mbhc->micbias_enable = false;
 53 
 54             mbhc->zl = mbhc->zr = 0;
 55             mbhc->is_hs_inserted = false;
 56             pr_debug("%s: Reporting removal (%x)\n",
 57                  __func__, mbhc->hph_status);
 58             wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
 59                         0, WCD_MBHC_JACK_MASK);
 60 
 61             if (mbhc->hph_status == SND_JACK_LINEOUT) {
 62 
 63                 pr_debug("%s: Enable micbias\n", __func__);
 64                 /* Disable current source and enable micbias */
 65                 snd_soc_update_bits(codec,
 66                     MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
 67                     0xB0, 0x80);
 68                 snd_soc_update_bits(codec,
 69                     MSM8X16_WCD_A_ANALOG_MICB_2_EN,
 70                     0x80, 0x80);
 71 
 72                 pr_debug("%s: set up elec removal detection\n",
 73                       __func__);
 74                 snd_soc_update_bits(codec,
 75                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
 76                     0x01, 0x00);
 77                 usleep_range(200, 210);
 78                 wcd9xxx_spmi_enable_irq(
 79                     mbhc->intr_ids->mbhc_hs_rem_intr);
 80             }
 81             mbhc->hph_status &= ~(SND_JACK_HEADSET |
 82                         SND_JACK_LINEOUT |
 83                         SND_JACK_UNSUPPORTED);
 84         }
 85 
 86         if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
 87             jack_type == SND_JACK_HEADPHONE)
 88             mbhc->hph_status &= ~SND_JACK_HEADSET;
 89 
 90         /* Report insertion */
 91         mbhc->hph_status |= jack_type;
 92 
 93         if (jack_type == SND_JACK_HEADPHONE)
 94             mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
 95         else if (jack_type == SND_JACK_UNSUPPORTED)
 96             mbhc->current_plug = MBHC_PLUG_TYPE_GND_MIC_SWAP;
 97         else if (jack_type == SND_JACK_HEADSET) {
 98             mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
 99             mbhc->jiffies_atreport = jiffies;
100         }
101         else if (jack_type == SND_JACK_LINEOUT)
102             mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
103 
104         if (mbhc->impedance_detect)
105             wcd_mbhc_calc_impedance(mbhc,
106                     &mbhc->zl, &mbhc->zr);
107         mbhc->is_hs_inserted = true;
108         pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
109              jack_type, mbhc->hph_status);
110         wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
111                     mbhc->hph_status, WCD_MBHC_JACK_MASK);
112         wcd_mbhc_clr_and_turnon_hph_padac(mbhc);
113     }
114     pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
115 }

View Code

 

1 static void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc,
2                 struct snd_soc_jack *jack, int status, int mask)
3 {
4     snd_soc_jack_report_no_dapm(jack, status, mask);
5 }

1 void snd_soc_jack_report_no_dapm(struct snd_soc_jack *jack, int status,
2                  int mask)
3 {
4     jack->status &= ~mask;
5     jack->status |= status & mask;
6 
7     snd_jack_report(jack->jack, jack->status);
8 }
9 EXPORT_SYMBOL_GPL(snd_soc_jack_report_no_dapm);

 1 void snd_jack_report(struct snd_jack *jack, int status)
 2 {
 3     int i;
 4 
 5     if (!jack)
 6         return;
 7 
 8     for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
 9         int testbit = SND_JACK_BTN_0 >> i;
10 
11         if (jack->type & testbit)
12             input_report_key(jack->input_dev, jack->key[i],
13                      status & testbit);
14     }
15 
16     for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
17         int testbit = 1 << i;
18         if (jack->type & testbit)
19             input_report_switch(jack->input_dev,
20                         jack_switch_types[i],
21                         status & testbit);
22     }
23 
24     input_sync(jack->input_dev);      //上报键值
25 }
26 EXPORT_SYMBOL(snd_jack_report);

 

说到底反映上去的管用数据是5   6   1 (插头类型 动铁耳机信号 值插入)

            0   0   0(同步)

 

插入的时候:

 图片 7

拔出的时候:

图片 8

接下来也足以依照联发科文书档案判断是还是不是是handset依然handphone:

图片 9

MediaTek是经过提请为/dev/input/event事件来规定的;

handset插入事件:

图片 10

handset拔出事件:

图片 11

2、kernel分析:

kernel/sound/soc/codecs/msm8x16-wcd.c

1 static const struct wcd_mbhc_intr intr_ids = {
2     .mbhc_sw_intr =  MSM8X16_WCD_IRQ_MBHC_HS_DET,
3     .mbhc_btn_press_intr = MSM8X16_WCD_IRQ_MBHC_PRESS,
4     .mbhc_btn_release_intr = MSM8X16_WCD_IRQ_MBHC_RELEASE,
5     .mbhc_hs_ins_intr = MSM8X16_WCD_IRQ_MBHC_INSREM_DET1,
6     .mbhc_hs_rem_intr = MSM8X16_WCD_IRQ_MBHC_INSREM_DET,
7     .hph_left_ocp = MSM8X16_WCD_IRQ_HPHL_OCP,
8     .hph_right_ocp = MSM8X16_WCD_IRQ_HPHR_OCP,
9 };

  这么些结构体描述了msm8909的wcdx连串的codec芯片的MBHC的音讯;

 

 

  1 static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
  2 {
  3     struct msm8x16_wcd_priv *msm8x16_wcd_priv;
  4     struct msm8x16_wcd *msm8x16_wcd;
  5     int i, ret;
  6 
  7     dev_dbg(codec->dev, "%s()\n", __func__);
  8 
  9     msm8x16_wcd_priv = kzalloc(sizeof(struct msm8x16_wcd_priv), GFP_KERNEL);
 10     if (!msm8x16_wcd_priv) {
 11         dev_err(codec->dev, "Failed to allocate private data\n");
 12         return -ENOMEM;
 13     }
 14 
 15     for (i = 0; i < NUM_DECIMATORS; i++) {
 16         tx_hpf_work[i].msm8x16_wcd = msm8x16_wcd_priv;
 17         tx_hpf_work[i].decimator = i + 1;
 18         INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
 19             tx_hpf_corner_freq_callback);
 20     }
 21 
 22     codec->control_data = dev_get_drvdata(codec->dev);
 23     snd_soc_codec_set_drvdata(codec, msm8x16_wcd_priv);
 24     msm8x16_wcd_priv->codec = codec;
 25 
 26     /* codec resmgr module init */
 27     msm8x16_wcd = codec->control_data;
 28     msm8x16_wcd->dig_base = ioremap(MSM8X16_DIGITAL_CODEC_BASE_ADDR,
 29                   MSM8X16_DIGITAL_CODEC_REG_SIZE);
 30     if (msm8x16_wcd->dig_base == NULL) {
 31         dev_err(codec->dev, "%s ioremap failed\n", __func__);
 32         kfree(msm8x16_wcd_priv);
 33         return -ENOMEM;
 34     }
 35     msm8x16_wcd_priv->spkdrv_reg =
 36         wcd8x16_wcd_codec_find_regulator(codec->control_data,
 37                         MSM89XX_VDD_SPKDRV_NAME);
 38     msm8x16_wcd_priv->pmic_rev = snd_soc_read(codec,
 39                     MSM8X16_WCD_A_DIGITAL_REVISION1);
 40     msm8x16_wcd_priv->codec_version = snd_soc_read(codec,
 41                     MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE);
 42     if (msm8x16_wcd_priv->codec_version == CONGA) {
 43         dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__,
 44                     msm8x16_wcd_priv->codec_version);
 45         msm8x16_wcd_priv->ext_spk_boost_set = true;
 46     } else {
 47         dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__,
 48                     msm8x16_wcd_priv->pmic_rev);
 49     }
 50     /*
 51      * set to default boost option BOOST_SWITCH, user mixer path can change
 52      * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
 53      */
 54     msm8x16_wcd_priv->boost_option = BOOST_SWITCH;
 55     msm8x16_wcd_dt_parse_boost_info(codec);    //
 56     msm8x16_wcd_set_boost_v(codec);
 57 
 58     snd_soc_add_codec_controls(codec, impedance_detect_controls,
 59                    ARRAY_SIZE(impedance_detect_controls));
 60 
 61     msm8x16_wcd_bringup(codec);
 62     msm8x16_wcd_codec_init_reg(codec);
 63     msm8x16_wcd_update_reg_defaults(codec);
 64 
 65     wcd9xxx_spmi_set_codec(codec);
 66 
 67     msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
 68                 wcd8x16_wcd_codec_find_regulator(
 69                 codec->control_data,
 70                 on_demand_supply_name[ON_DEMAND_MICBIAS]);
 71     atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
 72 
 73     BLOCKING_INIT_NOTIFIER_HEAD(&msm8x16_wcd_priv->notifier);
 74 
 75     msm8x16_wcd_priv->fw_data = kzalloc(sizeof(*(msm8x16_wcd_priv->fw_data))
 76             , GFP_KERNEL);
 77     if (!msm8x16_wcd_priv->fw_data) {
 78         dev_err(codec->dev, "Failed to allocate fw_data\n");
 79         iounmap(msm8x16_wcd->dig_base);
 80         kfree(msm8x16_wcd_priv);
 81         return -ENOMEM;
 82     }
 83 
 84     set_bit(WCD9XXX_MBHC_CAL, msm8x16_wcd_priv->fw_data->cal_bit);
 85     ret = wcd_cal_create_hwdep(msm8x16_wcd_priv->fw_data,
 86             WCD9XXX_CODEC_HWDEP_NODE, codec);
 87     if (ret < 0) {
 88         dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
 89         iounmap(msm8x16_wcd->dig_base);
 90         kfree(msm8x16_wcd_priv->fw_data);
 91         kfree(msm8x16_wcd_priv);
 92         return ret;
 93     }
 94 
 95     wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids,
 96             true);        //在这里获取到了相应的设备树信息
 97 
 98     msm8x16_wcd_priv->mclk_enabled = false;
 99     msm8x16_wcd_priv->clock_active = false;
100     msm8x16_wcd_priv->config_mode_active = false;
101 
102     /* Set initial MICBIAS voltage level */
103     msm8x16_wcd_set_micb_v(codec);
104 
105     /* Set initial cap mode */
106     msm8x16_wcd_configure_cap(codec, false, false);
107     registered_codec = codec;
108     modem_state_notifier =
109         subsys_notif_register_notifier("modem",
110                        &modem_state_notifier_block);
111     if (!modem_state_notifier) {
112         dev_err(codec->dev, "Failed to register modem state notifier\n"
113             );
114         iounmap(msm8x16_wcd->dig_base);
115         kfree(msm8x16_wcd_priv->fw_data);
116         kfree(msm8x16_wcd_priv);
117         registered_codec = NULL;
118         return -ENOMEM;
119     }
120     return 0;
121 }

 

kernel/sound/soc/codecs/wcd-mbhc-v2.c:

  1 int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
  2               const struct wcd_mbhc_cb *mbhc_cb,
  3               const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
  4               bool impedance_det_en)
  5 {
  6     int ret = 0;
  7     int hph_swh = 0;
  8     int gnd_swh = 0;
  9     struct snd_soc_card *card = codec->card;
 10     const char *hph_switch = "qcom,msm-mbhc-hphl-swh";
 11     const char *gnd_switch = "qcom,msm-mbhc-gnd-swh";
 12     const char *ext1_cap = "qcom,msm-micbias1-ext-cap";
 13     const char *ext2_cap = "qcom,msm-micbias2-ext-cap";
 14 
 15     pr_debug("%s: enter\n", __func__);
 16 
 17     ret = of_property_read_u32(card->dev->of_node, hph_switch, &hph_swh);    //在这里找到设备树信息,通过高低电平判断no或者nc的jack
 18     if (ret) {
 19         dev_err(card->dev,
 20             "%s: missing %s in dt node\n", __func__, hph_switch);
 21         goto err;
 22     }
 23 
 24     ret = of_property_read_u32(card->dev->of_node, gnd_switch, &gnd_swh);
 25     if (ret) {
 26         dev_err(card->dev,
 27             "%s: missing %s in dt node\n", __func__, gnd_switch);
 28         goto err;
 29     }
 30     mbhc->micbias1_cap_mode =
 31         (of_property_read_bool(card->dev->of_node, ext1_cap) ?
 32         MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
 33 
 34     mbhc->micbias2_cap_mode =
 35         (of_property_read_bool(card->dev->of_node, ext2_cap) ?
 36         MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
 37 
 38     mbhc->in_swch_irq_handler = false;
 39     mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
 40     mbhc->is_btn_press = false;
 41     mbhc->codec = codec;
 42     mbhc->intr_ids = mbhc_cdc_intr_ids;
 43     mbhc->impedance_detect = impedance_det_en;
 44     mbhc->hphl_swh = hph_swh;
 45     mbhc->gnd_swh = gnd_swh;
 46     mbhc->micbias_enable = false;
 47     mbhc->mbhc_cb = mbhc_cb;
 48     mbhc->btn_press_intr = false;
 49 
 50     if (mbhc->intr_ids == NULL) {
 51         pr_err("%s: Interrupt mapping not provided\n", __func__);
 52         return -EINVAL;
 53     }
 54 
 55     if (mbhc->headset_jack.jack == NULL) {
 56         ret = snd_soc_jack_new(codec, "Headset Jack",
 57                 WCD_MBHC_JACK_MASK, &mbhc->headset_jack);
 58         if (ret) {
 59             pr_err("%s: Failed to create new jack\n", __func__);
 60             return ret;
 61         }
 62 
 63         ret = snd_soc_jack_new(codec, "Button Jack",
 64                        WCD_MBHC_JACK_BUTTON_MASK,
 65                        &mbhc->button_jack);
 66         if (ret) {
 67             pr_err("Failed to create new jack\n");
 68             return ret;
 69         }
 70 
 71         ret = snd_jack_set_key(mbhc->button_jack.jack,
 72                        SND_JACK_BTN_0,
 73                        KEY_MEDIA);
 74         if (ret) {
 75             pr_err("%s: Failed to set code for btn-0\n",
 76                 __func__);
 77             return ret;
 78         }
 79 
 80         INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_lpress_fn);
 81     }
 82 
 83     /* Register event notifier */
 84     mbhc->nblock.notifier_call = wcd_event_notify;
 85     ret = msm8x16_register_notifier(codec, &mbhc->nblock);
 86     if (ret) {
 87         pr_err("%s: Failed to register notifier %d\n", __func__, ret);
 88         return ret;
 89     }
 90 
 91     init_waitqueue_head(&mbhc->wait_btn_press);
 92     mutex_init(&mbhc->codec_resource_lock);
 93 
 94     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_sw_intr,
 95                   wcd_mbhc_mech_plug_detect_irq,
 96                   "mbhc sw intr", mbhc);
 97     if (ret) {
 98         pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
 99                mbhc->intr_ids->mbhc_sw_intr, ret);
100         goto err_mbhc_sw_irq;
101     }
102 
103     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_btn_press_intr,
104                   wcd_mbhc_btn_press_handler,
105                   "Button Press detect",
106                   mbhc);
107     if (ret) {
108         pr_err("%s: Failed to request irq %d\n", __func__,
109                mbhc->intr_ids->mbhc_btn_press_intr);
110         goto err_btn_press_irq;
111     }
112 
113     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_btn_release_intr,
114                   wcd_mbhc_release_handler,
115                   "Button Release detect", mbhc);
116     if (ret) {
117         pr_err("%s: Failed to request irq %d\n", __func__,
118             mbhc->intr_ids->mbhc_btn_release_intr);
119         goto err_btn_release_irq;
120     }
121 
122     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_hs_ins_intr,
123                   wcd_mbhc_hs_ins_irq,
124                   "Elect Insert", mbhc);
125     if (ret) {
126         pr_err("%s: Failed to request irq %d\n", __func__,
127                mbhc->intr_ids->mbhc_hs_ins_intr);
128         goto err_mbhc_hs_ins_irq;
129     }
130     wcd9xxx_spmi_disable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
131 
132     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->mbhc_hs_rem_intr,
133                   wcd_mbhc_hs_rem_irq,
134                   "Elect Remove", mbhc);
135     if (ret) {
136         pr_err("%s: Failed to request irq %d\n", __func__,
137                mbhc->intr_ids->mbhc_hs_rem_intr);
138         goto err_mbhc_hs_rem_irq;
139     }
140     wcd9xxx_spmi_disable_irq(mbhc->intr_ids->mbhc_hs_rem_intr);
141 
142     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->hph_left_ocp,
143                   wcd_mbhc_hphl_ocp_irq, "HPH_L OCP detect",
144                   mbhc);                          //在这里申请对detect管脚的判断中断
145     if (ret) {
146         pr_err("%s: Failed to request irq %d\n", __func__,
147                mbhc->intr_ids->hph_left_ocp);
148         goto err_hphl_ocp_irq;
149     }
150 
151     ret = wcd9xxx_spmi_request_irq(mbhc->intr_ids->hph_right_ocp,
152                   wcd_mbhc_hphr_ocp_irq, "HPH_R OCP detect",
153                   mbhc);
154     if (ret) {
155         pr_err("%s: Failed to request irq %d\n", __func__,
156                mbhc->intr_ids->hph_right_ocp);
157         goto err_hphr_ocp_irq;
158     }
159 
160     pr_debug("%s: leave ret %d\n", __func__, ret);
161     return ret;
162 
163 err_hphr_ocp_irq:
164     wcd9xxx_spmi_free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
165 err_hphl_ocp_irq:
166     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
167 err_mbhc_hs_rem_irq:
168     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
169 err_mbhc_hs_ins_irq:
170     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
171 err_btn_release_irq:
172     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
173 err_btn_press_irq:
174     wcd9xxx_spmi_free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
175 err_mbhc_sw_irq:
176     msm8x16_unregister_notifier(codec, &mbhc->nblock);
177     mutex_destroy(&mbhc->codec_resource_lock);
178 err:
179     pr_debug("%s: leave ret %d\n", __func__, ret);
180     return ret;
181 }

 1 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
 2 {
 3     int r = IRQ_HANDLED;
 4     struct wcd_mbhc *mbhc = data;
 5 
 6     pr_debug("%s: enter\n", __func__);
 7     if (unlikely(wcd9xxx_spmi_lock_sleep() == false)) {
 8         pr_warn("%s: failed to hold suspend\n", __func__);
 9         r = IRQ_NONE;
10     } else {
11         /* Call handler */
12         wcd_mbhc_swch_irq_handler(mbhc);        //中断函数中的接口,负责处理相应的
13         wcd9xxx_spmi_unlock_sleep();
14     }
15     pr_debug("%s: leave %d\n", __func__, r);
16     return r;
17 }

  1 static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
  2 {
  3     bool detection_type;
  4     bool micbias1;
  5     struct snd_soc_codec *codec = mbhc->codec;
  6     pr_debug("%s: enter\n", __func__);
  7 
  8     WCD_MBHC_RSC_LOCK(mbhc);
  9 
 10     mbhc->in_swch_irq_handler = true;
 11 
 12     /* cancel pending button press */
 13     if (wcd_cancel_btn_work(mbhc))
 14         pr_debug("%s: button press is canceled\n", __func__);
 15 
 16     detection_type = (snd_soc_read(codec,
 17                 MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1)) & 0x20;
 18 
 19     /* Set the detection type appropriately */
 20     snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
 21             0x20, (!detection_type << 5));
 22 
 23     pr_debug("%s: mbhc->current_plug: %d detection_type: %d\n", __func__,
 24             mbhc->current_plug, detection_type);
 25     wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
 26 
 27     micbias1 = (snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN) & 0x80);
 28     if ((mbhc->current_plug == MBHC_PLUG_TYPE_NONE) &&
 29         detection_type) {
 30         /* Make sure MASTER_BIAS_CTL is enabled */
 31         snd_soc_update_bits(codec,
 32                     MSM8X16_WCD_A_ANALOG_MASTER_BIAS_CTL,
 33                     0x30, 0x30);
 34         snd_soc_update_bits(codec,
 35                 MSM8X16_WCD_A_ANALOG_MICB_1_EN,
 36                 0x04, 0x04);
 37         if (!mbhc->mbhc_cfg->hs_ext_micbias)
 38             /* Enable Tx2 RBias if the headset
 39              * is using internal micbias*/
 40             snd_soc_update_bits(codec,
 41                     MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS,
 42                     0x10, 0x10);
 43         /* Remove pull down on MIC BIAS2 */
 44         snd_soc_update_bits(codec,
 45                  MSM8X16_WCD_A_ANALOG_MICB_2_EN,
 46                 0x20, 0x00);
 47         /* Enable HW FSM */
 48         snd_soc_update_bits(codec,
 49                 MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
 50                 0x80, 0x80);
 51         /* Apply trim if needed on the device */
 52         if (mbhc->mbhc_cb && mbhc->mbhc_cb->trim_btn_reg)
 53             mbhc->mbhc_cb->trim_btn_reg(codec);
 54         /* Enable external voltage source to micbias if present */
 55         if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
 56             mbhc->mbhc_cb->enable_mb_source(codec, true);
 57         mbhc->btn_press_intr = false;
 58         wcd_mbhc_detect_plug_type(mbhc);
 59     } else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
 60             && !detection_type) {
 61         /* Disable external voltage source to micbias if present */
 62         if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
 63             mbhc->mbhc_cb->enable_mb_source(codec, false);
 64         /* Disable HW FSM */
 65         snd_soc_update_bits(codec,
 66                 MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
 67                 0xB0, 0x00);
 68         snd_soc_update_bits(codec,
 69                 MSM8X16_WCD_A_ANALOG_MICB_1_EN,
 70                 0x04, 0x00);
 71         if (mbhc->mbhc_cb && mbhc->mbhc_cb->set_cap_mode)
 72             mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
 73         mbhc->btn_press_intr = false;
 74         if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {        //如果判断是headphone,上报数据;
 75             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
 76         } else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
 77             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
 78         } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
 79             /* make sure to turn off Rbias */
 80             snd_soc_update_bits(codec,
 81                     MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS,
 82                     0x18, 0x08);
 83             snd_soc_update_bits(codec,
 84                     MSM8X16_WCD_A_ANALOG_MICB_2_EN,
 85                     0x20, 0x20);
 86             wcd9xxx_spmi_disable_irq(
 87                     mbhc->intr_ids->mbhc_hs_rem_intr);
 88             wcd9xxx_spmi_disable_irq(
 89                     mbhc->intr_ids->mbhc_hs_ins_intr);
 90             snd_soc_update_bits(codec,
 91                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
 92                     0x01, 0x01);
 93             snd_soc_update_bits(codec,
 94                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
 95                     0x06, 0x00);
 96             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
 97         } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) {
 98             mbhc->is_extn_cable = false;
 99             wcd9xxx_spmi_disable_irq(
100                     mbhc->intr_ids->mbhc_hs_rem_intr);
101             wcd9xxx_spmi_disable_irq(
102                     mbhc->intr_ids->mbhc_hs_ins_intr);
103             snd_soc_update_bits(codec,
104                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
105                     0x01, 0x01);
106             snd_soc_update_bits(codec,
107                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
108                     0x06, 0x00);
109             wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
110         }
111     } else if (!detection_type) {
112         /* Disable external voltage source to micbias if present */
113         if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
114             mbhc->mbhc_cb->enable_mb_source(codec, false);
115         /* Disable HW FSM */
116         snd_soc_update_bits(codec,
117                 MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
118                 0xB0, 0x00);
119     }
120 
121     mbhc->in_swch_irq_handler = false;
122     WCD_MBHC_RSC_UNLOCK(mbhc);
123     pr_debug("%s: leave\n", __func__);
124 }

 

由此一连串的检查和测试,判断是headset,headphones等,假设是headphones,最后经过wcd_mbhc_jack_report将数据反馈上去。

 

图片 12图片 13

  1 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
  2                 enum snd_jack_types jack_type)
  3 {
  4     struct snd_soc_codec *codec = mbhc->codec;
  5     WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
  6 
  7     pr_debug("%s: enter insertion %d hph_status %x\n",
  8          __func__, insertion, mbhc->hph_status);
  9     if (!insertion) {
 10         /* Report removal */
 11         mbhc->hph_status &= ~jack_type;
 12         /*
 13          * cancel possibly scheduled btn work and
 14          * report release if we reported button press
 15          */
 16         if (wcd_cancel_btn_work(mbhc)) {
 17             pr_debug("%s: button press is canceled\n", __func__);
 18         } else if (mbhc->buttons_pressed) {
 19             pr_debug("%s: release of button press%d\n",
 20                  __func__, jack_type);
 21             wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, 0,
 22                         mbhc->buttons_pressed);
 23             mbhc->buttons_pressed &=
 24                 ~WCD_MBHC_JACK_BUTTON_MASK;
 25         }
 26 
 27         if (mbhc->micbias_enable)
 28             mbhc->micbias_enable = false;
 29 
 30         mbhc->zl = mbhc->zr = 0;
 31         mbhc->is_hs_inserted = false;
 32         pr_debug("%s: Reporting removal %d(%x)\n", __func__,
 33              jack_type, mbhc->hph_status);
 34         wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
 35                 mbhc->hph_status, WCD_MBHC_JACK_MASK);
 36         wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
 37         hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
 38         hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
 39         mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
 40     } else {
 41         /*
 42          * Report removal of current jack type.
 43          * Headphone to headset shouldn't report headphone
 44          * removal.
 45          */
 46         if (mbhc->mbhc_cfg->detect_extn_cable &&
 47             (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH ||
 48             jack_type == SND_JACK_LINEOUT) &&
 49             (mbhc->hph_status && mbhc->hph_status != jack_type)) {
 50 
 51         if (mbhc->micbias_enable)
 52             mbhc->micbias_enable = false;
 53 
 54             mbhc->zl = mbhc->zr = 0;
 55             mbhc->is_hs_inserted = false;
 56             pr_debug("%s: Reporting removal (%x)\n",
 57                  __func__, mbhc->hph_status);
 58             wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
 59                         0, WCD_MBHC_JACK_MASK);
 60 
 61             if (mbhc->hph_status == SND_JACK_LINEOUT) {
 62 
 63                 pr_debug("%s: Enable micbias\n", __func__);
 64                 /* Disable current source and enable micbias */
 65                 snd_soc_update_bits(codec,
 66                     MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
 67                     0xB0, 0x80);
 68                 snd_soc_update_bits(codec,
 69                     MSM8X16_WCD_A_ANALOG_MICB_2_EN,
 70                     0x80, 0x80);
 71 
 72                 pr_debug("%s: set up elec removal detection\n",
 73                       __func__);
 74                 snd_soc_update_bits(codec,
 75                     MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
 76                     0x01, 0x00);
 77                 usleep_range(200, 210);
 78                 wcd9xxx_spmi_enable_irq(
 79                     mbhc->intr_ids->mbhc_hs_rem_intr);
 80             }
 81             mbhc->hph_status &= ~(SND_JACK_HEADSET |
 82                         SND_JACK_LINEOUT |
 83                         SND_JACK_UNSUPPORTED);
 84         }
 85 
 86         if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
 87             jack_type == SND_JACK_HEADPHONE)
 88             mbhc->hph_status &= ~SND_JACK_HEADSET;
 89 
 90         /* Report insertion */
 91         mbhc->hph_status |= jack_type;
 92 
 93         if (jack_type == SND_JACK_HEADPHONE)
 94             mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
 95         else if (jack_type == SND_JACK_UNSUPPORTED)
 96             mbhc->current_plug = MBHC_PLUG_TYPE_GND_MIC_SWAP;
 97         else if (jack_type == SND_JACK_HEADSET) {
 98             mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
 99             mbhc->jiffies_atreport = jiffies;
100         }
101         else if (jack_type == SND_JACK_LINEOUT)
102             mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
103 
104         if (mbhc->impedance_detect)
105             wcd_mbhc_calc_impedance(mbhc,
106                     &mbhc->zl, &mbhc->zr);
107         mbhc->is_hs_inserted = true;
108         pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
109              jack_type, mbhc->hph_status);
110         wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
111                     mbhc->hph_status, WCD_MBHC_JACK_MASK);
112         wcd_mbhc_clr_and_turnon_hph_padac(mbhc);
113     }
114     pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
115 }

View Code

 

1 static void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc,
2                 struct snd_soc_jack *jack, int status, int mask)
3 {
4     snd_soc_jack_report_no_dapm(jack, status, mask);
5 }

1 void snd_soc_jack_report_no_dapm(struct snd_soc_jack *jack, int status,
2                  int mask)
3 {
4     jack->status &= ~mask;
5     jack->status |= status & mask;
6 
7     snd_jack_report(jack->jack, jack->status);
8 }
9 EXPORT_SYMBOL_GPL(snd_soc_jack_report_no_dapm);

 1 void snd_jack_report(struct snd_jack *jack, int status)
 2 {
 3     int i;
 4 
 5     if (!jack)
 6         return;
 7 
 8     for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
 9         int testbit = SND_JACK_BTN_0 >> i;
10 
11         if (jack->type & testbit)
12             input_report_key(jack->input_dev, jack->key[i],
13                      status & testbit);
14     }
15 
16     for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
17         int testbit = 1 << i;
18         if (jack->type & testbit)
19             input_report_switch(jack->input_dev,
20                         jack_switch_types[i],
21                         status & testbit);
22     }
23 
24     input_sync(jack->input_dev);      //上报键值
25 }
26 EXPORT_SYMBOL(snd_jack_report);

 

最后反映上去的卓有成效数据是5   6   1 (插头类型 动铁耳机信号 值插入)

            0   0   0(同步)

 

陈设的时候:

 图片 14

拔出的时候:

图片 15

然后也足以依照MediaTek文书档案判断是不是是handset依旧handphone:

图片 16

MTK是通过提请为/dev/input/event事件来规定的;

handset插入事件:

图片 17

handset拔出事件:

图片 18