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 s ...
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);
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