这是基于8909平台代码跟踪。
硬件电路:在电源管理芯片PM8909上有个检测端口:HS_DET;
DTS配置:
在/arch/arm/boot/dts/qcom/msm-pm8909.dtsi中的spmi_bus下面有个qcom,pm8909@1中有如下配置:
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_dig又是kernel/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi中声卡配置的asoc-codec赋值,如下
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";
代码执行:
在/kernel/sound/soc/codecs/msm8x16-wcd.c中的msm8x16_wcd_spmi_probe中注册了soc_codec_dev_msm8x16_wcd的codec driver.
再开机过程中调入soc_codec_dev_msm8x16_wcd的probe函数msm8x16_wcd_codec_probe,probe函数通过wcd_mbhc_init进行对mbhc的初始化。
在wcd_mbhc_init函数中
if (mbhc->headset_jack.jack == NULL) {
ret = snd_soc_jack_new(codec, "Headset Jack",
WCD_MBHC_JACK_MASK, &mbhc->headset_jack);
if (ret) {
pr_err("%s: Failed to create new jack\n", __func__);
return ret;
}
注册一个新的后缀为"Headset Jack"的input设备;
在snd_soc_jack_new中主要是调用了snd_jack_new函数,进行下一步的调用;
int snd_jack_new(struct snd_card *card, const char *id, int type, struct snd_jack **jjack) { struct snd_jack *jack; int err; int i; static struct snd_device_ops ops = { .dev_free = snd_jack_dev_free, .dev_register = snd_jack_dev_register, }; jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); if (jack == NULL) return -ENOMEM; jack->id = kstrdup(id, GFP_KERNEL); jack->input_dev = input_allocate_device(); if (jack->input_dev == NULL) { err = -ENOMEM; goto fail_input; } jack->input_dev->phys = "ALSA"; jack->type = type; for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) if (type & (1 << i)) input_set_capability(jack->input_dev, EV_SW, jack_switch_types[i]); err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); if (err < 0) goto fail_input; *jjack = jack; return 0; fail_input: input_free_device(jack->input_dev); kfree(jack->id); kfree(jack); return err; }
在这个函数中新建了snd_device_ops ops并且调用了snd_device_new函数创建一个SNDRV_DEV_JACK设备。其中在snd_device_ops的snd_jack_dev_register函数中注册了input设备,代码如下:
static int snd_jack_dev_register(struct snd_device *device) { struct snd_jack *jack = device->device_data; struct snd_card *card = device->card; int err, i; snprintf(jack->name, sizeof(jack->name), "%s %s", card->shortname, jack->id); jack->input_dev->name = jack->name; /* Default to the sound card device. */ if (!jack->input_dev->dev.parent) jack->input_dev->dev.parent = snd_card_get_device_link(card); /* Add capabilities for any keys that are enabled */ for (i = 0; i < ARRAY_SIZE(jack->key); i++) { int testbit = SND_JACK_BTN_0 >> i; if (!(jack->type & testbit)) continue; if (!jack->key[i]) jack->key[i] = BTN_0 + i; input_set_capability(jack->input_dev, EV_KEY, jack->key[i]); } err = input_register_device(jack->input_dev); if (err == 0) jack->registered = 1; return err; }