高通msm8909耳機調試


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

 

 

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"來搜索關鍵字:

 

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狀態;根據高通bring up 手冊更改相應的DTSI:
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);    //通過snd_soc_jack_new()函數新建一個新的jack,將該jack指向Machine對應的CODEC,使該jack與CODEC建立聯系。snd_soc_jack_new -》snd_jack_new -》 snd_device_new - 》 snd_jack_dev_register -》

err = input_register_device(jack->input_dev); //最終注冊input設備

   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);                          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 }
//初始化函數,主要注冊了耳機插拔和耳機按鍵的input設備,注冊了耳機四個按鍵的鍵值,注冊了一系列的中斷,我們先看看其中比較重要的三個中斷,耳機插入中斷和按鍵按下松開中斷。
  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   /*讀取當前的檢測類型,如果detection_type = 1, 是指當前為插入,檢測插入耳機類型,如果為0,表示當前拔出*/
 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 *//*下面是使能一系列的micbias相關的寄存器,把micbias2使能*/
 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 */ /*如果micbias電壓是外供的,這里把它使能*/
 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);
       /*下面是檢測耳機拔出,耳機拔出后,關閉micbias電壓, 上報耳機拔出事件*/
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);
          /*如果當前是耳機延長線設備拔出,就關閉相關的中斷檢測,上報LINEOUT設備拔出事件*/
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將數據匯報上去。

 

  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(同步)

 

插入的時候:

 

拔出的時候:

然后也可以根據高通文檔判斷是否是handset還是handphone:

高通是通過申請為/dev/input/event事件來確定的;

handset插入事件:

handset拔出事件:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM