aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-07-29 08:32:56 -0400
committerTakashi Iwai <tiwai@suse.de>2009-07-29 08:32:56 -0400
commit3d21d3f7e7032619f5c5b47d3ee23bbe45de5993 (patch)
tree8cfb58a9c9d11c3f2aa17a2884bf8ea1bdc8afb3 /sound/pci/hda/patch_sigmatel.c
parent62558ce15759ee93223132258588320967e1e521 (diff)
ALSA: hda - Support auto-mic switching with IDT/STAC codec
Support the automatic mic-switching with some devices with IDT/STAC codecs. The condition is that the device has only two inputs, one for an external mic and one for an internal mic. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-rw-r--r--sound/pci/hda/patch_sigmatel.c170
1 files changed, 154 insertions, 16 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 307e86ceede1..f39dc98519a1 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -40,6 +40,7 @@ enum {
40 STAC_INSERT_EVENT, 40 STAC_INSERT_EVENT,
41 STAC_PWR_EVENT, 41 STAC_PWR_EVENT,
42 STAC_HP_EVENT, 42 STAC_HP_EVENT,
43 STAC_MIC_EVENT,
43}; 44};
44 45
45enum { 46enum {
@@ -176,6 +177,12 @@ struct sigmatel_jack {
176 struct snd_jack *jack; 177 struct snd_jack *jack;
177}; 178};
178 179
180struct sigmatel_mic_route {
181 hda_nid_t pin;
182 unsigned char mux_idx;
183 unsigned char dmux_idx;
184};
185
179struct sigmatel_spec { 186struct sigmatel_spec {
180 struct snd_kcontrol_new *mixers[4]; 187 struct snd_kcontrol_new *mixers[4];
181 unsigned int num_mixers; 188 unsigned int num_mixers;
@@ -187,6 +194,7 @@ struct sigmatel_spec {
187 unsigned int hp_detect: 1; 194 unsigned int hp_detect: 1;
188 unsigned int spdif_mute: 1; 195 unsigned int spdif_mute: 1;
189 unsigned int check_volume_offset:1; 196 unsigned int check_volume_offset:1;
197 unsigned int auto_mic:1;
190 198
191 /* gpio lines */ 199 /* gpio lines */
192 unsigned int eapd_mask; 200 unsigned int eapd_mask;
@@ -243,6 +251,9 @@ struct sigmatel_spec {
243 unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ 251 unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
244 unsigned int num_caps; /* number of capture volume/switch elements */ 252 unsigned int num_caps; /* number of capture volume/switch elements */
245 253
254 struct sigmatel_mic_route ext_mic;
255 struct sigmatel_mic_route int_mic;
256
246 const char **spdif_labels; 257 const char **spdif_labels;
247 258
248 hda_nid_t dig_in_nid; 259 hda_nid_t dig_in_nid;
@@ -1304,7 +1315,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
1304 if (err < 0) 1315 if (err < 0)
1305 return err; 1316 return err;
1306 } 1317 }
1307 if (spec->num_dmuxes > 0) { 1318 if (!spec->auto_mic && spec->num_dmuxes > 0) {
1308 stac_dmux_mixer.count = spec->num_dmuxes; 1319 stac_dmux_mixer.count = spec->num_dmuxes;
1309 err = snd_hda_ctl_add(codec, 1320 err = snd_hda_ctl_add(codec,
1310 snd_ctl_new1(&stac_dmux_mixer, codec)); 1321 snd_ctl_new1(&stac_dmux_mixer, codec));
@@ -2950,6 +2961,8 @@ static int stac92xx_add_input_source(struct sigmatel_spec *spec)
2950 struct snd_kcontrol_new *knew; 2961 struct snd_kcontrol_new *knew;
2951 struct hda_input_mux *imux = &spec->private_imux; 2962 struct hda_input_mux *imux = &spec->private_imux;
2952 2963
2964 if (spec->auto_mic)
2965 return 0; /* no need for input source */
2953 if (!spec->num_adcs || imux->num_items <= 1) 2966 if (!spec->num_adcs || imux->num_items <= 1)
2954 return 0; /* no need for input source control */ 2967 return 0; /* no need for input source control */
2955 knew = stac_control_new(spec, &stac_input_src_temp, 2968 knew = stac_control_new(spec, &stac_input_src_temp,
@@ -3557,14 +3570,26 @@ static const char *stac92xx_dmic_labels[5] = {
3557 "Digital Mic 3", "Digital Mic 4" 3570 "Digital Mic 3", "Digital Mic 4"
3558}; 3571};
3559 3572
3573static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
3574 hda_nid_t nid)
3575{
3576 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
3577 int i, nums;
3578
3579 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
3580 for (i = 0; i < nums; i++)
3581 if (conn[i] == nid)
3582 return i;
3583 return -1;
3584}
3585
3560/* create playback/capture controls for input pins on dmic capable codecs */ 3586/* create playback/capture controls for input pins on dmic capable codecs */
3561static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, 3587static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3562 const struct auto_pin_cfg *cfg) 3588 const struct auto_pin_cfg *cfg)
3563{ 3589{
3564 struct sigmatel_spec *spec = codec->spec; 3590 struct sigmatel_spec *spec = codec->spec;
3565 struct hda_input_mux *dimux = &spec->private_dimux; 3591 struct hda_input_mux *dimux = &spec->private_dimux;
3566 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; 3592 int err, i;
3567 int err, i, j;
3568 char name[32]; 3593 char name[32];
3569 3594
3570 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; 3595 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
@@ -3574,7 +3599,6 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3574 for (i = 0; i < spec->num_dmics; i++) { 3599 for (i = 0; i < spec->num_dmics; i++) {
3575 hda_nid_t nid; 3600 hda_nid_t nid;
3576 int index; 3601 int index;
3577 int num_cons;
3578 unsigned int wcaps; 3602 unsigned int wcaps;
3579 unsigned int def_conf; 3603 unsigned int def_conf;
3580 3604
@@ -3583,17 +3607,10 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3583 continue; 3607 continue;
3584 3608
3585 nid = spec->dmic_nids[i]; 3609 nid = spec->dmic_nids[i];
3586 num_cons = snd_hda_get_connections(codec, 3610 index = get_connection_index(codec, spec->dmux_nids[0], nid);
3587 spec->dmux_nids[0], 3611 if (index < 0)
3588 con_lst, 3612 continue;
3589 HDA_MAX_NUM_INPUTS); 3613
3590 for (j = 0; j < num_cons; j++)
3591 if (con_lst[j] == nid) {
3592 index = j;
3593 goto found;
3594 }
3595 continue;
3596found:
3597 wcaps = get_wcaps(codec, nid) & 3614 wcaps = get_wcaps(codec, nid) &
3598 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); 3615 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
3599 3616
@@ -3620,6 +3637,88 @@ found:
3620 return 0; 3637 return 0;
3621} 3638}
3622 3639
3640static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
3641 hda_nid_t *fixed, hda_nid_t *ext)
3642{
3643 unsigned int cfg;
3644
3645 if (!nid)
3646 return 0;
3647 cfg = snd_hda_codec_get_pincfg(codec, nid);
3648 switch (get_defcfg_connect(cfg)) {
3649 case AC_JACK_PORT_FIXED:
3650 if (*fixed)
3651 return 1; /* already occupied */
3652 *fixed = nid;
3653 break;
3654 case AC_JACK_PORT_COMPLEX:
3655 if (*ext)
3656 return 1; /* already occupied */
3657 *ext = nid;
3658 break;
3659 }
3660 return 0;
3661}
3662
3663static int set_mic_route(struct hda_codec *codec,
3664 struct sigmatel_mic_route *mic,
3665 hda_nid_t pin)
3666{
3667 struct sigmatel_spec *spec = codec->spec;
3668 struct auto_pin_cfg *cfg = &spec->autocfg;
3669 int i;
3670
3671 mic->pin = pin;
3672 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
3673 if (pin == cfg->input_pins[i])
3674 break;
3675 if (i <= AUTO_PIN_FRONT_MIC) {
3676 /* analog pin */
3677 mic->dmux_idx = 0;
3678 i = get_connection_index(codec, spec->mux_nids[0], pin);
3679 if (i < 0)
3680 return -1;
3681 mic->mux_idx = i;
3682 } else {
3683 /* digital pin */
3684 mic->mux_idx = 0;
3685 i = get_connection_index(codec, spec->dmux_nids[0], pin);
3686 if (i < 0)
3687 return -1;
3688 mic->dmux_idx = i;
3689 }
3690 return 0;
3691}
3692
3693/* return non-zero if the device is for automatic mic switch */
3694static int stac_check_auto_mic(struct hda_codec *codec)
3695{
3696 struct sigmatel_spec *spec = codec->spec;
3697 struct auto_pin_cfg *cfg = &spec->autocfg;
3698 hda_nid_t fixed, ext;
3699 int i;
3700
3701 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
3702 if (cfg->input_pins[i])
3703 return 0; /* must be exclusively mics */
3704 }
3705 fixed = ext = 0;
3706 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
3707 if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
3708 return 0;
3709 for (i = 0; i < spec->num_dmics; i++)
3710 if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
3711 return 0;
3712 if (!fixed || !ext)
3713 return 0;
3714 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
3715 return 0; /* no unsol support */
3716 if (set_mic_route(codec, &spec->ext_mic, ext) ||
3717 set_mic_route(codec, &spec->int_mic, fixed))
3718 return 0; /* something is wrong */
3719 return 1;
3720}
3721
3623/* create playback/capture controls for input pins */ 3722/* create playback/capture controls for input pins */
3624static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) 3723static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3625{ 3724{
@@ -3837,6 +3936,14 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
3837 spec->autocfg.line_outs = 0; 3936 spec->autocfg.line_outs = 0;
3838 } 3937 }
3839 3938
3939 if (stac_check_auto_mic(codec)) {
3940 spec->auto_mic = 1;
3941 /* only one capture for auto-mic */
3942 spec->num_adcs = 1;
3943 spec->num_caps = 1;
3944 spec->num_muxes = 1;
3945 }
3946
3840 for (i = 0; i < spec->num_caps; i++) { 3947 for (i = 0; i < spec->num_caps; i++) {
3841 err = stac92xx_add_capvol_ctls(codec, spec->capvols[i], 3948 err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
3842 spec->capsws[i], i); 3949 spec->capsws[i], i);
@@ -4264,6 +4371,10 @@ static int stac92xx_init(struct hda_codec *codec)
4264 for (i = 0; i < cfg->hp_outs; i++) 4371 for (i = 0; i < cfg->hp_outs; i++)
4265 stac_toggle_power_map(codec, cfg->hp_pins[i], 1); 4372 stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
4266 } 4373 }
4374 if (spec->auto_mic) {
4375 if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
4376 stac_issue_unsol_event(codec, spec->ext_mic.pin);
4377 }
4267 for (i = 0; i < AUTO_PIN_LAST; i++) { 4378 for (i = 0; i < AUTO_PIN_LAST; i++) {
4268 hda_nid_t nid = cfg->input_pins[i]; 4379 hda_nid_t nid = cfg->input_pins[i];
4269 if (nid) { 4380 if (nid) {
@@ -4601,6 +4712,25 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
4601 } 4712 }
4602} 4713}
4603 4714
4715static void stac92xx_mic_detect(struct hda_codec *codec)
4716{
4717 struct sigmatel_spec *spec = codec->spec;
4718 struct sigmatel_mic_route *mic;
4719
4720 if (get_pin_presence(codec, spec->ext_mic.pin))
4721 mic = &spec->ext_mic;
4722 else
4723 mic = &spec->int_mic;
4724 if (mic->dmux_idx)
4725 snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
4726 AC_VERB_SET_CONNECT_SEL,
4727 mic->dmux_idx);
4728 else
4729 snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
4730 AC_VERB_SET_CONNECT_SEL,
4731 mic->mux_idx);
4732}
4733
4604static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) 4734static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
4605{ 4735{
4606 struct sigmatel_event *event = stac_get_event(codec, nid); 4736 struct sigmatel_event *event = stac_get_event(codec, nid);
@@ -4623,7 +4753,15 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
4623 switch (event->type) { 4753 switch (event->type) {
4624 case STAC_HP_EVENT: 4754 case STAC_HP_EVENT:
4625 stac92xx_hp_detect(codec); 4755 stac92xx_hp_detect(codec);
4626 /* fallthru */ 4756 break;
4757 case STAC_MIC_EVENT:
4758 stac92xx_mic_detect(codec);
4759 break;
4760 }
4761
4762 switch (event->type) {
4763 case STAC_HP_EVENT:
4764 case STAC_MIC_EVENT:
4627 case STAC_INSERT_EVENT: 4765 case STAC_INSERT_EVENT:
4628 case STAC_PWR_EVENT: 4766 case STAC_PWR_EVENT:
4629 if (spec->num_pwrs > 0) 4767 if (spec->num_pwrs > 0)