diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1085 |
1 files changed, 808 insertions, 277 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ad97d937d3a8..4f37477d3c71 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -39,6 +39,7 @@ | |||
39 | 39 | ||
40 | #define CONEXANT_HP_EVENT 0x37 | 40 | #define CONEXANT_HP_EVENT 0x37 |
41 | #define CONEXANT_MIC_EVENT 0x38 | 41 | #define CONEXANT_MIC_EVENT 0x38 |
42 | #define CONEXANT_LINE_EVENT 0x39 | ||
42 | 43 | ||
43 | /* Conexant 5051 specific */ | 44 | /* Conexant 5051 specific */ |
44 | 45 | ||
@@ -55,9 +56,16 @@ struct pin_dac_pair { | |||
55 | int type; | 56 | int type; |
56 | }; | 57 | }; |
57 | 58 | ||
59 | struct imux_info { | ||
60 | hda_nid_t pin; /* input pin NID */ | ||
61 | hda_nid_t adc; /* connected ADC NID */ | ||
62 | hda_nid_t boost; /* optional boost volume NID */ | ||
63 | int index; /* corresponding to autocfg.input */ | ||
64 | }; | ||
65 | |||
58 | struct conexant_spec { | 66 | struct conexant_spec { |
59 | 67 | ||
60 | struct snd_kcontrol_new *mixers[5]; | 68 | const struct snd_kcontrol_new *mixers[5]; |
61 | int num_mixers; | 69 | int num_mixers; |
62 | hda_nid_t vmaster_nid; | 70 | hda_nid_t vmaster_nid; |
63 | 71 | ||
@@ -74,14 +82,17 @@ struct conexant_spec { | |||
74 | */ | 82 | */ |
75 | unsigned int cur_eapd; | 83 | unsigned int cur_eapd; |
76 | unsigned int hp_present; | 84 | unsigned int hp_present; |
85 | unsigned int line_present; | ||
77 | unsigned int auto_mic; | 86 | unsigned int auto_mic; |
78 | int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ | 87 | int auto_mic_ext; /* imux_pins[] index for ext mic */ |
88 | int auto_mic_dock; /* imux_pins[] index for dock mic */ | ||
89 | int auto_mic_int; /* imux_pins[] index for int mic */ | ||
79 | unsigned int need_dac_fix; | 90 | unsigned int need_dac_fix; |
80 | hda_nid_t slave_dig_outs[2]; | 91 | hda_nid_t slave_dig_outs[2]; |
81 | 92 | ||
82 | /* capture */ | 93 | /* capture */ |
83 | unsigned int num_adc_nids; | 94 | unsigned int num_adc_nids; |
84 | hda_nid_t *adc_nids; | 95 | const hda_nid_t *adc_nids; |
85 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | 96 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
86 | 97 | ||
87 | unsigned int cur_adc_idx; | 98 | unsigned int cur_adc_idx; |
@@ -89,9 +100,11 @@ struct conexant_spec { | |||
89 | unsigned int cur_adc_stream_tag; | 100 | unsigned int cur_adc_stream_tag; |
90 | unsigned int cur_adc_format; | 101 | unsigned int cur_adc_format; |
91 | 102 | ||
103 | const struct hda_pcm_stream *capture_stream; | ||
104 | |||
92 | /* capture source */ | 105 | /* capture source */ |
93 | const struct hda_input_mux *input_mux; | 106 | const struct hda_input_mux *input_mux; |
94 | hda_nid_t *capsrc_nids; | 107 | const hda_nid_t *capsrc_nids; |
95 | unsigned int cur_mux[3]; | 108 | unsigned int cur_mux[3]; |
96 | 109 | ||
97 | /* channel model */ | 110 | /* channel model */ |
@@ -106,12 +119,17 @@ struct conexant_spec { | |||
106 | /* dynamic controls, init_verbs and input_mux */ | 119 | /* dynamic controls, init_verbs and input_mux */ |
107 | struct auto_pin_cfg autocfg; | 120 | struct auto_pin_cfg autocfg; |
108 | struct hda_input_mux private_imux; | 121 | struct hda_input_mux private_imux; |
122 | struct imux_info imux_info[HDA_MAX_NUM_INPUTS]; | ||
123 | hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS]; | ||
109 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 124 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
110 | struct pin_dac_pair dac_info[8]; | 125 | struct pin_dac_pair dac_info[8]; |
111 | int dac_info_filled; | 126 | int dac_info_filled; |
112 | 127 | ||
113 | unsigned int port_d_mode; | 128 | unsigned int port_d_mode; |
114 | unsigned int auto_mute:1; /* used in auto-parser */ | 129 | unsigned int auto_mute:1; /* used in auto-parser */ |
130 | unsigned int detect_line:1; /* Line-out detection enabled */ | ||
131 | unsigned int automute_lines:1; /* automute line-out as well */ | ||
132 | unsigned int automute_hp_lo:1; /* both HP and LO available */ | ||
115 | unsigned int dell_automute:1; | 133 | unsigned int dell_automute:1; |
116 | unsigned int dell_vostro:1; | 134 | unsigned int dell_vostro:1; |
117 | unsigned int ideapad:1; | 135 | unsigned int ideapad:1; |
@@ -119,6 +137,8 @@ struct conexant_spec { | |||
119 | unsigned int hp_laptop:1; | 137 | unsigned int hp_laptop:1; |
120 | unsigned int asus:1; | 138 | unsigned int asus:1; |
121 | 139 | ||
140 | unsigned int adc_switching:1; | ||
141 | |||
122 | unsigned int ext_mic_present; | 142 | unsigned int ext_mic_present; |
123 | unsigned int recording; | 143 | unsigned int recording; |
124 | void (*capture_prepare)(struct hda_codec *codec); | 144 | void (*capture_prepare)(struct hda_codec *codec); |
@@ -227,7 +247,7 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
227 | 247 | ||
228 | 248 | ||
229 | 249 | ||
230 | static struct hda_pcm_stream conexant_pcm_analog_playback = { | 250 | static const struct hda_pcm_stream conexant_pcm_analog_playback = { |
231 | .substreams = 1, | 251 | .substreams = 1, |
232 | .channels_min = 2, | 252 | .channels_min = 2, |
233 | .channels_max = 2, | 253 | .channels_max = 2, |
@@ -239,7 +259,7 @@ static struct hda_pcm_stream conexant_pcm_analog_playback = { | |||
239 | }, | 259 | }, |
240 | }; | 260 | }; |
241 | 261 | ||
242 | static struct hda_pcm_stream conexant_pcm_analog_capture = { | 262 | static const struct hda_pcm_stream conexant_pcm_analog_capture = { |
243 | .substreams = 1, | 263 | .substreams = 1, |
244 | .channels_min = 2, | 264 | .channels_min = 2, |
245 | .channels_max = 2, | 265 | .channels_max = 2, |
@@ -251,7 +271,7 @@ static struct hda_pcm_stream conexant_pcm_analog_capture = { | |||
251 | }; | 271 | }; |
252 | 272 | ||
253 | 273 | ||
254 | static struct hda_pcm_stream conexant_pcm_digital_playback = { | 274 | static const struct hda_pcm_stream conexant_pcm_digital_playback = { |
255 | .substreams = 1, | 275 | .substreams = 1, |
256 | .channels_min = 2, | 276 | .channels_min = 2, |
257 | .channels_max = 2, | 277 | .channels_max = 2, |
@@ -263,7 +283,7 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = { | |||
263 | }, | 283 | }, |
264 | }; | 284 | }; |
265 | 285 | ||
266 | static struct hda_pcm_stream conexant_pcm_digital_capture = { | 286 | static const struct hda_pcm_stream conexant_pcm_digital_capture = { |
267 | .substreams = 1, | 287 | .substreams = 1, |
268 | .channels_min = 2, | 288 | .channels_min = 2, |
269 | .channels_max = 2, | 289 | .channels_max = 2, |
@@ -294,7 +314,7 @@ static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
294 | return 0; | 314 | return 0; |
295 | } | 315 | } |
296 | 316 | ||
297 | static struct hda_pcm_stream cx5051_pcm_analog_capture = { | 317 | static const struct hda_pcm_stream cx5051_pcm_analog_capture = { |
298 | .substreams = 1, | 318 | .substreams = 1, |
299 | .channels_min = 2, | 319 | .channels_min = 2, |
300 | .channels_max = 2, | 320 | .channels_max = 2, |
@@ -319,13 +339,19 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
319 | spec->multiout.max_channels; | 339 | spec->multiout.max_channels; |
320 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 340 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
321 | spec->multiout.dac_nids[0]; | 341 | spec->multiout.dac_nids[0]; |
322 | if (codec->vendor_id == 0x14f15051) | 342 | if (spec->capture_stream) |
323 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | 343 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; |
324 | cx5051_pcm_analog_capture; | 344 | else { |
325 | else | 345 | if (codec->vendor_id == 0x14f15051) |
326 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | 346 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = |
327 | conexant_pcm_analog_capture; | 347 | cx5051_pcm_analog_capture; |
328 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | 348 | else { |
349 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
350 | conexant_pcm_analog_capture; | ||
351 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = | ||
352 | spec->num_adc_nids; | ||
353 | } | ||
354 | } | ||
329 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 355 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
330 | 356 | ||
331 | if (spec->multiout.dig_out_nid) { | 357 | if (spec->multiout.dig_out_nid) { |
@@ -433,7 +459,7 @@ static void conexant_free(struct hda_codec *codec) | |||
433 | kfree(codec->spec); | 459 | kfree(codec->spec); |
434 | } | 460 | } |
435 | 461 | ||
436 | static struct snd_kcontrol_new cxt_capture_mixers[] = { | 462 | static const struct snd_kcontrol_new cxt_capture_mixers[] = { |
437 | { | 463 | { |
438 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 464 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
439 | .name = "Capture Source", | 465 | .name = "Capture Source", |
@@ -446,7 +472,7 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { | |||
446 | 472 | ||
447 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 473 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
448 | /* additional beep mixers; the actual parameters are overwritten at build */ | 474 | /* additional beep mixers; the actual parameters are overwritten at build */ |
449 | static struct snd_kcontrol_new cxt_beep_mixer[] = { | 475 | static const struct snd_kcontrol_new cxt_beep_mixer[] = { |
450 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), | 476 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), |
451 | HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), | 477 | HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), |
452 | { } /* end */ | 478 | { } /* end */ |
@@ -456,12 +482,18 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = { | |||
456 | static const char * const slave_vols[] = { | 482 | static const char * const slave_vols[] = { |
457 | "Headphone Playback Volume", | 483 | "Headphone Playback Volume", |
458 | "Speaker Playback Volume", | 484 | "Speaker Playback Volume", |
485 | "Front Playback Volume", | ||
486 | "Surround Playback Volume", | ||
487 | "CLFE Playback Volume", | ||
459 | NULL | 488 | NULL |
460 | }; | 489 | }; |
461 | 490 | ||
462 | static const char * const slave_sws[] = { | 491 | static const char * const slave_sws[] = { |
463 | "Headphone Playback Switch", | 492 | "Headphone Playback Switch", |
464 | "Speaker Playback Switch", | 493 | "Speaker Playback Switch", |
494 | "Front Playback Switch", | ||
495 | "Surround Playback Switch", | ||
496 | "CLFE Playback Switch", | ||
465 | NULL | 497 | NULL |
466 | }; | 498 | }; |
467 | 499 | ||
@@ -521,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec) | |||
521 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 553 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
522 | /* create beep controls if needed */ | 554 | /* create beep controls if needed */ |
523 | if (spec->beep_amp) { | 555 | if (spec->beep_amp) { |
524 | struct snd_kcontrol_new *knew; | 556 | const struct snd_kcontrol_new *knew; |
525 | for (knew = cxt_beep_mixer; knew->name; knew++) { | 557 | for (knew = cxt_beep_mixer; knew->name; knew++) { |
526 | struct snd_kcontrol *kctl; | 558 | struct snd_kcontrol *kctl; |
527 | kctl = snd_ctl_new1(knew, codec); | 559 | kctl = snd_ctl_new1(knew, codec); |
@@ -546,7 +578,7 @@ static int conexant_suspend(struct hda_codec *codec, pm_message_t state) | |||
546 | } | 578 | } |
547 | #endif | 579 | #endif |
548 | 580 | ||
549 | static struct hda_codec_ops conexant_patch_ops = { | 581 | static const struct hda_codec_ops conexant_patch_ops = { |
550 | .build_controls = conexant_build_controls, | 582 | .build_controls = conexant_build_controls, |
551 | .build_pcms = conexant_build_pcms, | 583 | .build_pcms = conexant_build_pcms, |
552 | .init = conexant_init, | 584 | .init = conexant_init, |
@@ -564,6 +596,7 @@ static struct hda_codec_ops conexant_patch_ops = { | |||
564 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ | 596 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ |
565 | #endif | 597 | #endif |
566 | 598 | ||
599 | static int patch_conexant_auto(struct hda_codec *codec); | ||
567 | /* | 600 | /* |
568 | * EAPD control | 601 | * EAPD control |
569 | * the private value = nid | (invert << 8) | 602 | * the private value = nid | (invert << 8) |
@@ -662,16 +695,16 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
662 | 695 | ||
663 | /* Conexant 5045 specific */ | 696 | /* Conexant 5045 specific */ |
664 | 697 | ||
665 | static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; | 698 | static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; |
666 | static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; | 699 | static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; |
667 | static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; | 700 | static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; |
668 | #define CXT5045_SPDIF_OUT 0x18 | 701 | #define CXT5045_SPDIF_OUT 0x18 |
669 | 702 | ||
670 | static struct hda_channel_mode cxt5045_modes[1] = { | 703 | static const struct hda_channel_mode cxt5045_modes[1] = { |
671 | { 2, NULL }, | 704 | { 2, NULL }, |
672 | }; | 705 | }; |
673 | 706 | ||
674 | static struct hda_input_mux cxt5045_capture_source = { | 707 | static const struct hda_input_mux cxt5045_capture_source = { |
675 | .num_items = 2, | 708 | .num_items = 2, |
676 | .items = { | 709 | .items = { |
677 | { "IntMic", 0x1 }, | 710 | { "IntMic", 0x1 }, |
@@ -679,7 +712,7 @@ static struct hda_input_mux cxt5045_capture_source = { | |||
679 | } | 712 | } |
680 | }; | 713 | }; |
681 | 714 | ||
682 | static struct hda_input_mux cxt5045_capture_source_benq = { | 715 | static const struct hda_input_mux cxt5045_capture_source_benq = { |
683 | .num_items = 5, | 716 | .num_items = 5, |
684 | .items = { | 717 | .items = { |
685 | { "IntMic", 0x1 }, | 718 | { "IntMic", 0x1 }, |
@@ -690,7 +723,7 @@ static struct hda_input_mux cxt5045_capture_source_benq = { | |||
690 | } | 723 | } |
691 | }; | 724 | }; |
692 | 725 | ||
693 | static struct hda_input_mux cxt5045_capture_source_hp530 = { | 726 | static const struct hda_input_mux cxt5045_capture_source_hp530 = { |
694 | .num_items = 2, | 727 | .num_items = 2, |
695 | .items = { | 728 | .items = { |
696 | { "ExtMic", 0x1 }, | 729 | { "ExtMic", 0x1 }, |
@@ -723,7 +756,7 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
723 | } | 756 | } |
724 | 757 | ||
725 | /* bind volumes of both NID 0x10 and 0x11 */ | 758 | /* bind volumes of both NID 0x10 and 0x11 */ |
726 | static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { | 759 | static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { |
727 | .ops = &snd_hda_bind_vol, | 760 | .ops = &snd_hda_bind_vol, |
728 | .values = { | 761 | .values = { |
729 | HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), | 762 | HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), |
@@ -735,12 +768,12 @@ static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { | |||
735 | /* toggle input of built-in and mic jack appropriately */ | 768 | /* toggle input of built-in and mic jack appropriately */ |
736 | static void cxt5045_hp_automic(struct hda_codec *codec) | 769 | static void cxt5045_hp_automic(struct hda_codec *codec) |
737 | { | 770 | { |
738 | static struct hda_verb mic_jack_on[] = { | 771 | static const struct hda_verb mic_jack_on[] = { |
739 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 772 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
740 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 773 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, |
741 | {} | 774 | {} |
742 | }; | 775 | }; |
743 | static struct hda_verb mic_jack_off[] = { | 776 | static const struct hda_verb mic_jack_off[] = { |
744 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 777 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
745 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 778 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, |
746 | {} | 779 | {} |
@@ -784,7 +817,7 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, | |||
784 | } | 817 | } |
785 | } | 818 | } |
786 | 819 | ||
787 | static struct snd_kcontrol_new cxt5045_mixers[] = { | 820 | static const struct snd_kcontrol_new cxt5045_mixers[] = { |
788 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), | 821 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), |
789 | HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), | 822 | HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), |
790 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), | 823 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), |
@@ -808,7 +841,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
808 | {} | 841 | {} |
809 | }; | 842 | }; |
810 | 843 | ||
811 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | 844 | static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { |
812 | HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), | 845 | HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), |
813 | HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), | 846 | HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), |
814 | HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), | 847 | HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), |
@@ -825,7 +858,7 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | |||
825 | {} | 858 | {} |
826 | }; | 859 | }; |
827 | 860 | ||
828 | static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | 861 | static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { |
829 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), | 862 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), |
830 | HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), | 863 | HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), |
831 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), | 864 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), |
@@ -849,7 +882,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | |||
849 | {} | 882 | {} |
850 | }; | 883 | }; |
851 | 884 | ||
852 | static struct hda_verb cxt5045_init_verbs[] = { | 885 | static const struct hda_verb cxt5045_init_verbs[] = { |
853 | /* Line in, Mic */ | 886 | /* Line in, Mic */ |
854 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | 887 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
855 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | 888 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
@@ -875,7 +908,7 @@ static struct hda_verb cxt5045_init_verbs[] = { | |||
875 | { } /* end */ | 908 | { } /* end */ |
876 | }; | 909 | }; |
877 | 910 | ||
878 | static struct hda_verb cxt5045_benq_init_verbs[] = { | 911 | static const struct hda_verb cxt5045_benq_init_verbs[] = { |
879 | /* Internal Mic, Mic */ | 912 | /* Internal Mic, Mic */ |
880 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | 913 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
881 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | 914 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
@@ -901,13 +934,13 @@ static struct hda_verb cxt5045_benq_init_verbs[] = { | |||
901 | { } /* end */ | 934 | { } /* end */ |
902 | }; | 935 | }; |
903 | 936 | ||
904 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { | 937 | static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { |
905 | /* pin sensing on HP jack */ | 938 | /* pin sensing on HP jack */ |
906 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | 939 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, |
907 | { } /* end */ | 940 | { } /* end */ |
908 | }; | 941 | }; |
909 | 942 | ||
910 | static struct hda_verb cxt5045_mic_sense_init_verbs[] = { | 943 | static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { |
911 | /* pin sensing on HP jack */ | 944 | /* pin sensing on HP jack */ |
912 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | 945 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, |
913 | { } /* end */ | 946 | { } /* end */ |
@@ -917,7 +950,7 @@ static struct hda_verb cxt5045_mic_sense_init_verbs[] = { | |||
917 | /* Test configuration for debugging, modelled after the ALC260 test | 950 | /* Test configuration for debugging, modelled after the ALC260 test |
918 | * configuration. | 951 | * configuration. |
919 | */ | 952 | */ |
920 | static struct hda_input_mux cxt5045_test_capture_source = { | 953 | static const struct hda_input_mux cxt5045_test_capture_source = { |
921 | .num_items = 5, | 954 | .num_items = 5, |
922 | .items = { | 955 | .items = { |
923 | { "MIXER", 0x0 }, | 956 | { "MIXER", 0x0 }, |
@@ -928,7 +961,7 @@ static struct hda_input_mux cxt5045_test_capture_source = { | |||
928 | }, | 961 | }, |
929 | }; | 962 | }; |
930 | 963 | ||
931 | static struct snd_kcontrol_new cxt5045_test_mixer[] = { | 964 | static const struct snd_kcontrol_new cxt5045_test_mixer[] = { |
932 | 965 | ||
933 | /* Output controls */ | 966 | /* Output controls */ |
934 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), | 967 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), |
@@ -978,7 +1011,7 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { | |||
978 | { } /* end */ | 1011 | { } /* end */ |
979 | }; | 1012 | }; |
980 | 1013 | ||
981 | static struct hda_verb cxt5045_test_init_verbs[] = { | 1014 | static const struct hda_verb cxt5045_test_init_verbs[] = { |
982 | /* Set connections */ | 1015 | /* Set connections */ |
983 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | 1016 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, |
984 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, | 1017 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, |
@@ -1047,6 +1080,7 @@ enum { | |||
1047 | #ifdef CONFIG_SND_DEBUG | 1080 | #ifdef CONFIG_SND_DEBUG |
1048 | CXT5045_TEST, | 1081 | CXT5045_TEST, |
1049 | #endif | 1082 | #endif |
1083 | CXT5045_AUTO, | ||
1050 | CXT5045_MODELS | 1084 | CXT5045_MODELS |
1051 | }; | 1085 | }; |
1052 | 1086 | ||
@@ -1059,9 +1093,10 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { | |||
1059 | #ifdef CONFIG_SND_DEBUG | 1093 | #ifdef CONFIG_SND_DEBUG |
1060 | [CXT5045_TEST] = "test", | 1094 | [CXT5045_TEST] = "test", |
1061 | #endif | 1095 | #endif |
1096 | [CXT5045_AUTO] = "auto", | ||
1062 | }; | 1097 | }; |
1063 | 1098 | ||
1064 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | 1099 | static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { |
1065 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), | 1100 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), |
1066 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", | 1101 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", |
1067 | CXT5045_LAPTOP_HPSENSE), | 1102 | CXT5045_LAPTOP_HPSENSE), |
@@ -1085,6 +1120,16 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1085 | struct conexant_spec *spec; | 1120 | struct conexant_spec *spec; |
1086 | int board_config; | 1121 | int board_config; |
1087 | 1122 | ||
1123 | board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, | ||
1124 | cxt5045_models, | ||
1125 | cxt5045_cfg_tbl); | ||
1126 | #if 0 /* use the old method just for safety */ | ||
1127 | if (board_config < 0) | ||
1128 | board_config = CXT5045_AUTO; | ||
1129 | #endif | ||
1130 | if (board_config == CXT5045_AUTO) | ||
1131 | return patch_conexant_auto(codec); | ||
1132 | |||
1088 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1133 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1089 | if (!spec) | 1134 | if (!spec) |
1090 | return -ENOMEM; | 1135 | return -ENOMEM; |
@@ -1111,9 +1156,6 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1111 | 1156 | ||
1112 | codec->patch_ops = conexant_patch_ops; | 1157 | codec->patch_ops = conexant_patch_ops; |
1113 | 1158 | ||
1114 | board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, | ||
1115 | cxt5045_models, | ||
1116 | cxt5045_cfg_tbl); | ||
1117 | switch (board_config) { | 1159 | switch (board_config) { |
1118 | case CXT5045_LAPTOP_HPSENSE: | 1160 | case CXT5045_LAPTOP_HPSENSE: |
1119 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | 1161 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; |
@@ -1196,15 +1238,15 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1196 | /* Conexant 5047 specific */ | 1238 | /* Conexant 5047 specific */ |
1197 | #define CXT5047_SPDIF_OUT 0x11 | 1239 | #define CXT5047_SPDIF_OUT 0x11 |
1198 | 1240 | ||
1199 | static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ | 1241 | static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ |
1200 | static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; | 1242 | static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; |
1201 | static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; | 1243 | static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; |
1202 | 1244 | ||
1203 | static struct hda_channel_mode cxt5047_modes[1] = { | 1245 | static const struct hda_channel_mode cxt5047_modes[1] = { |
1204 | { 2, NULL }, | 1246 | { 2, NULL }, |
1205 | }; | 1247 | }; |
1206 | 1248 | ||
1207 | static struct hda_input_mux cxt5047_toshiba_capture_source = { | 1249 | static const struct hda_input_mux cxt5047_toshiba_capture_source = { |
1208 | .num_items = 2, | 1250 | .num_items = 2, |
1209 | .items = { | 1251 | .items = { |
1210 | { "ExtMic", 0x2 }, | 1252 | { "ExtMic", 0x2 }, |
@@ -1256,12 +1298,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) | |||
1256 | /* toggle input of built-in and mic jack appropriately */ | 1298 | /* toggle input of built-in and mic jack appropriately */ |
1257 | static void cxt5047_hp_automic(struct hda_codec *codec) | 1299 | static void cxt5047_hp_automic(struct hda_codec *codec) |
1258 | { | 1300 | { |
1259 | static struct hda_verb mic_jack_on[] = { | 1301 | static const struct hda_verb mic_jack_on[] = { |
1260 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1302 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
1261 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1303 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1262 | {} | 1304 | {} |
1263 | }; | 1305 | }; |
1264 | static struct hda_verb mic_jack_off[] = { | 1306 | static const struct hda_verb mic_jack_off[] = { |
1265 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1307 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
1266 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1308 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1267 | {} | 1309 | {} |
@@ -1289,7 +1331,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec, | |||
1289 | } | 1331 | } |
1290 | } | 1332 | } |
1291 | 1333 | ||
1292 | static struct snd_kcontrol_new cxt5047_base_mixers[] = { | 1334 | static const struct snd_kcontrol_new cxt5047_base_mixers[] = { |
1293 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), | 1335 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), |
1294 | HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), | 1336 | HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), |
1295 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), | 1337 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), |
@@ -1309,19 +1351,19 @@ static struct snd_kcontrol_new cxt5047_base_mixers[] = { | |||
1309 | {} | 1351 | {} |
1310 | }; | 1352 | }; |
1311 | 1353 | ||
1312 | static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { | 1354 | static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { |
1313 | /* See the note in cxt5047_hp_master_sw_put */ | 1355 | /* See the note in cxt5047_hp_master_sw_put */ |
1314 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), | 1356 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), |
1315 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), | 1357 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), |
1316 | {} | 1358 | {} |
1317 | }; | 1359 | }; |
1318 | 1360 | ||
1319 | static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { | 1361 | static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { |
1320 | HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), | 1362 | HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), |
1321 | { } /* end */ | 1363 | { } /* end */ |
1322 | }; | 1364 | }; |
1323 | 1365 | ||
1324 | static struct hda_verb cxt5047_init_verbs[] = { | 1366 | static const struct hda_verb cxt5047_init_verbs[] = { |
1325 | /* Line in, Mic, Built-in Mic */ | 1367 | /* Line in, Mic, Built-in Mic */ |
1326 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 1368 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
1327 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, | 1369 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, |
@@ -1348,7 +1390,7 @@ static struct hda_verb cxt5047_init_verbs[] = { | |||
1348 | }; | 1390 | }; |
1349 | 1391 | ||
1350 | /* configuration for Toshiba Laptops */ | 1392 | /* configuration for Toshiba Laptops */ |
1351 | static struct hda_verb cxt5047_toshiba_init_verbs[] = { | 1393 | static const struct hda_verb cxt5047_toshiba_init_verbs[] = { |
1352 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ | 1394 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ |
1353 | {} | 1395 | {} |
1354 | }; | 1396 | }; |
@@ -1357,7 +1399,7 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = { | |||
1357 | * configuration. | 1399 | * configuration. |
1358 | */ | 1400 | */ |
1359 | #ifdef CONFIG_SND_DEBUG | 1401 | #ifdef CONFIG_SND_DEBUG |
1360 | static struct hda_input_mux cxt5047_test_capture_source = { | 1402 | static const struct hda_input_mux cxt5047_test_capture_source = { |
1361 | .num_items = 4, | 1403 | .num_items = 4, |
1362 | .items = { | 1404 | .items = { |
1363 | { "LINE1 pin", 0x0 }, | 1405 | { "LINE1 pin", 0x0 }, |
@@ -1367,7 +1409,7 @@ static struct hda_input_mux cxt5047_test_capture_source = { | |||
1367 | }, | 1409 | }, |
1368 | }; | 1410 | }; |
1369 | 1411 | ||
1370 | static struct snd_kcontrol_new cxt5047_test_mixer[] = { | 1412 | static const struct snd_kcontrol_new cxt5047_test_mixer[] = { |
1371 | 1413 | ||
1372 | /* Output only controls */ | 1414 | /* Output only controls */ |
1373 | HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), | 1415 | HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), |
@@ -1420,7 +1462,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { | |||
1420 | { } /* end */ | 1462 | { } /* end */ |
1421 | }; | 1463 | }; |
1422 | 1464 | ||
1423 | static struct hda_verb cxt5047_test_init_verbs[] = { | 1465 | static const struct hda_verb cxt5047_test_init_verbs[] = { |
1424 | /* Enable retasking pins as output, initially without power amp */ | 1466 | /* Enable retasking pins as output, initially without power amp */ |
1425 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 1467 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1426 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 1468 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
@@ -1492,6 +1534,7 @@ enum { | |||
1492 | #ifdef CONFIG_SND_DEBUG | 1534 | #ifdef CONFIG_SND_DEBUG |
1493 | CXT5047_TEST, | 1535 | CXT5047_TEST, |
1494 | #endif | 1536 | #endif |
1537 | CXT5047_AUTO, | ||
1495 | CXT5047_MODELS | 1538 | CXT5047_MODELS |
1496 | }; | 1539 | }; |
1497 | 1540 | ||
@@ -1502,9 +1545,10 @@ static const char * const cxt5047_models[CXT5047_MODELS] = { | |||
1502 | #ifdef CONFIG_SND_DEBUG | 1545 | #ifdef CONFIG_SND_DEBUG |
1503 | [CXT5047_TEST] = "test", | 1546 | [CXT5047_TEST] = "test", |
1504 | #endif | 1547 | #endif |
1548 | [CXT5047_AUTO] = "auto", | ||
1505 | }; | 1549 | }; |
1506 | 1550 | ||
1507 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | 1551 | static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { |
1508 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | 1552 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), |
1509 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", | 1553 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", |
1510 | CXT5047_LAPTOP), | 1554 | CXT5047_LAPTOP), |
@@ -1517,6 +1561,16 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1517 | struct conexant_spec *spec; | 1561 | struct conexant_spec *spec; |
1518 | int board_config; | 1562 | int board_config; |
1519 | 1563 | ||
1564 | board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, | ||
1565 | cxt5047_models, | ||
1566 | cxt5047_cfg_tbl); | ||
1567 | #if 0 /* not enabled as default, as BIOS often broken for this codec */ | ||
1568 | if (board_config < 0) | ||
1569 | board_config = CXT5047_AUTO; | ||
1570 | #endif | ||
1571 | if (board_config == CXT5047_AUTO) | ||
1572 | return patch_conexant_auto(codec); | ||
1573 | |||
1520 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1574 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1521 | if (!spec) | 1575 | if (!spec) |
1522 | return -ENOMEM; | 1576 | return -ENOMEM; |
@@ -1540,9 +1594,6 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1540 | 1594 | ||
1541 | codec->patch_ops = conexant_patch_ops; | 1595 | codec->patch_ops = conexant_patch_ops; |
1542 | 1596 | ||
1543 | board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, | ||
1544 | cxt5047_models, | ||
1545 | cxt5047_cfg_tbl); | ||
1546 | switch (board_config) { | 1597 | switch (board_config) { |
1547 | case CXT5047_LAPTOP: | 1598 | case CXT5047_LAPTOP: |
1548 | spec->num_mixers = 2; | 1599 | spec->num_mixers = 2; |
@@ -1591,10 +1642,10 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1591 | } | 1642 | } |
1592 | 1643 | ||
1593 | /* Conexant 5051 specific */ | 1644 | /* Conexant 5051 specific */ |
1594 | static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; | 1645 | static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; |
1595 | static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; | 1646 | static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; |
1596 | 1647 | ||
1597 | static struct hda_channel_mode cxt5051_modes[1] = { | 1648 | static const struct hda_channel_mode cxt5051_modes[1] = { |
1598 | { 2, NULL }, | 1649 | { 2, NULL }, |
1599 | }; | 1650 | }; |
1600 | 1651 | ||
@@ -1696,7 +1747,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, | |||
1696 | snd_hda_input_jack_report(codec, nid); | 1747 | snd_hda_input_jack_report(codec, nid); |
1697 | } | 1748 | } |
1698 | 1749 | ||
1699 | static struct snd_kcontrol_new cxt5051_playback_mixers[] = { | 1750 | static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { |
1700 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 1751 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), |
1701 | { | 1752 | { |
1702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1753 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1709,7 +1760,7 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = { | |||
1709 | {} | 1760 | {} |
1710 | }; | 1761 | }; |
1711 | 1762 | ||
1712 | static struct snd_kcontrol_new cxt5051_capture_mixers[] = { | 1763 | static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { |
1713 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | 1764 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), |
1714 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1765 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1715 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), | 1766 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), |
@@ -1719,7 +1770,7 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = { | |||
1719 | {} | 1770 | {} |
1720 | }; | 1771 | }; |
1721 | 1772 | ||
1722 | static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | 1773 | static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { |
1723 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | 1774 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), |
1724 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1775 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1725 | HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), | 1776 | HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), |
@@ -1727,19 +1778,19 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | |||
1727 | {} | 1778 | {} |
1728 | }; | 1779 | }; |
1729 | 1780 | ||
1730 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | 1781 | static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { |
1731 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), | 1782 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), |
1732 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), | 1783 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), |
1733 | {} | 1784 | {} |
1734 | }; | 1785 | }; |
1735 | 1786 | ||
1736 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | 1787 | static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { |
1737 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), | 1788 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), |
1738 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), | 1789 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), |
1739 | {} | 1790 | {} |
1740 | }; | 1791 | }; |
1741 | 1792 | ||
1742 | static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { | 1793 | static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { |
1743 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | 1794 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), |
1744 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1795 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1745 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), | 1796 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), |
@@ -1747,7 +1798,7 @@ static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { | |||
1747 | {} | 1798 | {} |
1748 | }; | 1799 | }; |
1749 | 1800 | ||
1750 | static struct hda_verb cxt5051_init_verbs[] = { | 1801 | static const struct hda_verb cxt5051_init_verbs[] = { |
1751 | /* Line in, Mic */ | 1802 | /* Line in, Mic */ |
1752 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | 1803 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, |
1753 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1804 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1776,7 +1827,7 @@ static struct hda_verb cxt5051_init_verbs[] = { | |||
1776 | { } /* end */ | 1827 | { } /* end */ |
1777 | }; | 1828 | }; |
1778 | 1829 | ||
1779 | static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | 1830 | static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { |
1780 | /* Line in, Mic */ | 1831 | /* Line in, Mic */ |
1781 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | 1832 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, |
1782 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1833 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1801,7 +1852,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | |||
1801 | { } /* end */ | 1852 | { } /* end */ |
1802 | }; | 1853 | }; |
1803 | 1854 | ||
1804 | static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | 1855 | static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { |
1805 | /* Line in, Mic */ | 1856 | /* Line in, Mic */ |
1806 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | 1857 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, |
1807 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1858 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1834,7 +1885,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1834 | { } /* end */ | 1885 | { } /* end */ |
1835 | }; | 1886 | }; |
1836 | 1887 | ||
1837 | static struct hda_verb cxt5051_f700_init_verbs[] = { | 1888 | static const struct hda_verb cxt5051_f700_init_verbs[] = { |
1838 | /* Line in, Mic */ | 1889 | /* Line in, Mic */ |
1839 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | 1890 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, |
1840 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1891 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1869,7 +1920,7 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, | |||
1869 | snd_hda_input_jack_report(codec, nid); | 1920 | snd_hda_input_jack_report(codec, nid); |
1870 | } | 1921 | } |
1871 | 1922 | ||
1872 | static struct hda_verb cxt5051_ideapad_init_verbs[] = { | 1923 | static const struct hda_verb cxt5051_ideapad_init_verbs[] = { |
1873 | /* Subwoofer */ | 1924 | /* Subwoofer */ |
1874 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 1925 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1875 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | 1926 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -1906,6 +1957,7 @@ enum { | |||
1906 | CXT5051_F700, /* HP Compaq Presario F700 */ | 1957 | CXT5051_F700, /* HP Compaq Presario F700 */ |
1907 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | 1958 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ |
1908 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ | 1959 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ |
1960 | CXT5051_AUTO, /* auto-parser */ | ||
1909 | CXT5051_MODELS | 1961 | CXT5051_MODELS |
1910 | }; | 1962 | }; |
1911 | 1963 | ||
@@ -1917,9 +1969,10 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { | |||
1917 | [CXT5051_F700] = "hp-700", | 1969 | [CXT5051_F700] = "hp-700", |
1918 | [CXT5051_TOSHIBA] = "toshiba", | 1970 | [CXT5051_TOSHIBA] = "toshiba", |
1919 | [CXT5051_IDEAPAD] = "ideapad", | 1971 | [CXT5051_IDEAPAD] = "ideapad", |
1972 | [CXT5051_AUTO] = "auto", | ||
1920 | }; | 1973 | }; |
1921 | 1974 | ||
1922 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1975 | static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
1923 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), | 1976 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), |
1924 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), | 1977 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), |
1925 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), | 1978 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), |
@@ -1937,6 +1990,16 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1937 | struct conexant_spec *spec; | 1990 | struct conexant_spec *spec; |
1938 | int board_config; | 1991 | int board_config; |
1939 | 1992 | ||
1993 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1994 | cxt5051_models, | ||
1995 | cxt5051_cfg_tbl); | ||
1996 | #if 0 /* use the old method just for safety */ | ||
1997 | if (board_config < 0) | ||
1998 | board_config = CXT5051_AUTO; | ||
1999 | #endif | ||
2000 | if (board_config == CXT5051_AUTO) | ||
2001 | return patch_conexant_auto(codec); | ||
2002 | |||
1940 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2003 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1941 | if (!spec) | 2004 | if (!spec) |
1942 | return -ENOMEM; | 2005 | return -ENOMEM; |
@@ -1967,9 +2030,6 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1967 | 2030 | ||
1968 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | 2031 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; |
1969 | 2032 | ||
1970 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1971 | cxt5051_models, | ||
1972 | cxt5051_cfg_tbl); | ||
1973 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; | 2033 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; |
1974 | switch (board_config) { | 2034 | switch (board_config) { |
1975 | case CXT5051_HP: | 2035 | case CXT5051_HP: |
@@ -2011,17 +2071,17 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
2011 | 2071 | ||
2012 | /* Conexant 5066 specific */ | 2072 | /* Conexant 5066 specific */ |
2013 | 2073 | ||
2014 | static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; | 2074 | static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; |
2015 | static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; | 2075 | static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; |
2016 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; | 2076 | static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; |
2017 | static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; | 2077 | static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; |
2018 | 2078 | ||
2019 | /* OLPC's microphone port is DC coupled for use with external sensors, | 2079 | /* OLPC's microphone port is DC coupled for use with external sensors, |
2020 | * therefore we use a 50% mic bias in order to center the input signal with | 2080 | * therefore we use a 50% mic bias in order to center the input signal with |
2021 | * the DC input range of the codec. */ | 2081 | * the DC input range of the codec. */ |
2022 | #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 | 2082 | #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 |
2023 | 2083 | ||
2024 | static struct hda_channel_mode cxt5066_modes[1] = { | 2084 | static const struct hda_channel_mode cxt5066_modes[1] = { |
2025 | { 2, NULL }, | 2085 | { 2, NULL }, |
2026 | }; | 2086 | }; |
2027 | 2087 | ||
@@ -2176,7 +2236,7 @@ static void cxt5066_vostro_automic(struct hda_codec *codec) | |||
2176 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2236 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2177 | {} | 2237 | {} |
2178 | }; | 2238 | }; |
2179 | static struct hda_verb ext_mic_absent[] = { | 2239 | static const struct hda_verb ext_mic_absent[] = { |
2180 | /* enable internal mic, port C */ | 2240 | /* enable internal mic, port C */ |
2181 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2241 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
2182 | 2242 | ||
@@ -2209,7 +2269,7 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) | |||
2209 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2269 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2210 | {} | 2270 | {} |
2211 | }; | 2271 | }; |
2212 | static struct hda_verb ext_mic_absent[] = { | 2272 | static const struct hda_verb ext_mic_absent[] = { |
2213 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | 2273 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
2214 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2274 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
2215 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2275 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2257,7 +2317,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) | |||
2257 | { | 2317 | { |
2258 | unsigned int ext_present, dock_present; | 2318 | unsigned int ext_present, dock_present; |
2259 | 2319 | ||
2260 | static struct hda_verb ext_mic_present[] = { | 2320 | static const struct hda_verb ext_mic_present[] = { |
2261 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | 2321 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, |
2262 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | 2322 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, |
2263 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2323 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -2265,7 +2325,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) | |||
2265 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2325 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2266 | {} | 2326 | {} |
2267 | }; | 2327 | }; |
2268 | static struct hda_verb dock_mic_present[] = { | 2328 | static const struct hda_verb dock_mic_present[] = { |
2269 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | 2329 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, |
2270 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2330 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
2271 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2331 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -2273,7 +2333,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) | |||
2273 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2333 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2274 | {} | 2334 | {} |
2275 | }; | 2335 | }; |
2276 | static struct hda_verb ext_mic_absent[] = { | 2336 | static const struct hda_verb ext_mic_absent[] = { |
2277 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | 2337 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
2278 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2338 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
2279 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2339 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2537,7 +2597,7 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | |||
2537 | } | 2597 | } |
2538 | 2598 | ||
2539 | static void conexant_check_dig_outs(struct hda_codec *codec, | 2599 | static void conexant_check_dig_outs(struct hda_codec *codec, |
2540 | hda_nid_t *dig_pins, | 2600 | const hda_nid_t *dig_pins, |
2541 | int num_pins) | 2601 | int num_pins) |
2542 | { | 2602 | { |
2543 | struct conexant_spec *spec = codec->spec; | 2603 | struct conexant_spec *spec = codec->spec; |
@@ -2557,7 +2617,7 @@ static void conexant_check_dig_outs(struct hda_codec *codec, | |||
2557 | } | 2617 | } |
2558 | } | 2618 | } |
2559 | 2619 | ||
2560 | static struct hda_input_mux cxt5066_capture_source = { | 2620 | static const struct hda_input_mux cxt5066_capture_source = { |
2561 | .num_items = 4, | 2621 | .num_items = 4, |
2562 | .items = { | 2622 | .items = { |
2563 | { "Mic B", 0 }, | 2623 | { "Mic B", 0 }, |
@@ -2567,7 +2627,7 @@ static struct hda_input_mux cxt5066_capture_source = { | |||
2567 | }, | 2627 | }, |
2568 | }; | 2628 | }; |
2569 | 2629 | ||
2570 | static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { | 2630 | static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { |
2571 | .ops = &snd_hda_bind_vol, | 2631 | .ops = &snd_hda_bind_vol, |
2572 | .values = { | 2632 | .values = { |
2573 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), | 2633 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), |
@@ -2576,7 +2636,7 @@ static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { | |||
2576 | }, | 2636 | }, |
2577 | }; | 2637 | }; |
2578 | 2638 | ||
2579 | static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { | 2639 | static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { |
2580 | .ops = &snd_hda_bind_sw, | 2640 | .ops = &snd_hda_bind_sw, |
2581 | .values = { | 2641 | .values = { |
2582 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), | 2642 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), |
@@ -2585,12 +2645,12 @@ static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { | |||
2585 | }, | 2645 | }, |
2586 | }; | 2646 | }; |
2587 | 2647 | ||
2588 | static struct snd_kcontrol_new cxt5066_mixer_master[] = { | 2648 | static const struct snd_kcontrol_new cxt5066_mixer_master[] = { |
2589 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 2649 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), |
2590 | {} | 2650 | {} |
2591 | }; | 2651 | }; |
2592 | 2652 | ||
2593 | static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | 2653 | static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { |
2594 | { | 2654 | { |
2595 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2655 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2596 | .name = "Master Playback Volume", | 2656 | .name = "Master Playback Volume", |
@@ -2609,7 +2669,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2609 | {} | 2669 | {} |
2610 | }; | 2670 | }; |
2611 | 2671 | ||
2612 | static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | 2672 | static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { |
2613 | { | 2673 | { |
2614 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2674 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2615 | .name = "DC Mode Enable Switch", | 2675 | .name = "DC Mode Enable Switch", |
@@ -2627,7 +2687,7 @@ static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | |||
2627 | {} | 2687 | {} |
2628 | }; | 2688 | }; |
2629 | 2689 | ||
2630 | static struct snd_kcontrol_new cxt5066_mixers[] = { | 2690 | static const struct snd_kcontrol_new cxt5066_mixers[] = { |
2631 | { | 2691 | { |
2632 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2692 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2633 | .name = "Master Playback Switch", | 2693 | .name = "Master Playback Switch", |
@@ -2650,7 +2710,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2650 | {} | 2710 | {} |
2651 | }; | 2711 | }; |
2652 | 2712 | ||
2653 | static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | 2713 | static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { |
2654 | { | 2714 | { |
2655 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2656 | .name = "Internal Mic Boost Capture Enum", | 2716 | .name = "Internal Mic Boost Capture Enum", |
@@ -2662,7 +2722,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | |||
2662 | {} | 2722 | {} |
2663 | }; | 2723 | }; |
2664 | 2724 | ||
2665 | static struct hda_verb cxt5066_init_verbs[] = { | 2725 | static const struct hda_verb cxt5066_init_verbs[] = { |
2666 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | 2726 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ |
2667 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | 2727 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ |
2668 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | 2728 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ |
@@ -2717,7 +2777,7 @@ static struct hda_verb cxt5066_init_verbs[] = { | |||
2717 | { } /* end */ | 2777 | { } /* end */ |
2718 | }; | 2778 | }; |
2719 | 2779 | ||
2720 | static struct hda_verb cxt5066_init_verbs_olpc[] = { | 2780 | static const struct hda_verb cxt5066_init_verbs_olpc[] = { |
2721 | /* Port A: headphones */ | 2781 | /* Port A: headphones */ |
2722 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 2782 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
2723 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2783 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
@@ -2778,7 +2838,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2778 | { } /* end */ | 2838 | { } /* end */ |
2779 | }; | 2839 | }; |
2780 | 2840 | ||
2781 | static struct hda_verb cxt5066_init_verbs_vostro[] = { | 2841 | static const struct hda_verb cxt5066_init_verbs_vostro[] = { |
2782 | /* Port A: headphones */ | 2842 | /* Port A: headphones */ |
2783 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2843 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2784 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2844 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
@@ -2839,7 +2899,7 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { | |||
2839 | { } /* end */ | 2899 | { } /* end */ |
2840 | }; | 2900 | }; |
2841 | 2901 | ||
2842 | static struct hda_verb cxt5066_init_verbs_ideapad[] = { | 2902 | static const struct hda_verb cxt5066_init_verbs_ideapad[] = { |
2843 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | 2903 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ |
2844 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | 2904 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ |
2845 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | 2905 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ |
@@ -2889,7 +2949,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { | |||
2889 | { } /* end */ | 2949 | { } /* end */ |
2890 | }; | 2950 | }; |
2891 | 2951 | ||
2892 | static struct hda_verb cxt5066_init_verbs_thinkpad[] = { | 2952 | static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { |
2893 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | 2953 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ |
2894 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ | 2954 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ |
2895 | 2955 | ||
@@ -2947,13 +3007,13 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = { | |||
2947 | { } /* end */ | 3007 | { } /* end */ |
2948 | }; | 3008 | }; |
2949 | 3009 | ||
2950 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 3010 | static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { |
2951 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 3011 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2952 | { } /* end */ | 3012 | { } /* end */ |
2953 | }; | 3013 | }; |
2954 | 3014 | ||
2955 | 3015 | ||
2956 | static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { | 3016 | static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { |
2957 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, | 3017 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, |
2958 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | 3018 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, |
2959 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | 3019 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, |
@@ -2997,6 +3057,7 @@ enum { | |||
2997 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ | 3057 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ |
2998 | CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ | 3058 | CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ |
2999 | CXT5066_HP_LAPTOP, /* HP Laptop */ | 3059 | CXT5066_HP_LAPTOP, /* HP Laptop */ |
3060 | CXT5066_AUTO, /* BIOS auto-parser */ | ||
3000 | CXT5066_MODELS | 3061 | CXT5066_MODELS |
3001 | }; | 3062 | }; |
3002 | 3063 | ||
@@ -3009,9 +3070,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = { | |||
3009 | [CXT5066_THINKPAD] = "thinkpad", | 3070 | [CXT5066_THINKPAD] = "thinkpad", |
3010 | [CXT5066_ASUS] = "asus", | 3071 | [CXT5066_ASUS] = "asus", |
3011 | [CXT5066_HP_LAPTOP] = "hp-laptop", | 3072 | [CXT5066_HP_LAPTOP] = "hp-laptop", |
3073 | [CXT5066_AUTO] = "auto", | ||
3012 | }; | 3074 | }; |
3013 | 3075 | ||
3014 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 3076 | static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
3015 | SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), | 3077 | SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), |
3016 | SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), | 3078 | SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), |
3017 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), | 3079 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), |
@@ -3046,6 +3108,15 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3046 | struct conexant_spec *spec; | 3108 | struct conexant_spec *spec; |
3047 | int board_config; | 3109 | int board_config; |
3048 | 3110 | ||
3111 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | ||
3112 | cxt5066_models, cxt5066_cfg_tbl); | ||
3113 | #if 0 /* use the old method just for safety */ | ||
3114 | if (board_config < 0) | ||
3115 | board_config = CXT5066_AUTO; | ||
3116 | #endif | ||
3117 | if (board_config == CXT5066_AUTO) | ||
3118 | return patch_conexant_auto(codec); | ||
3119 | |||
3049 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3120 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
3050 | if (!spec) | 3121 | if (!spec) |
3051 | return -ENOMEM; | 3122 | return -ENOMEM; |
@@ -3076,8 +3147,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3076 | 3147 | ||
3077 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); | 3148 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); |
3078 | 3149 | ||
3079 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | ||
3080 | cxt5066_models, cxt5066_cfg_tbl); | ||
3081 | switch (board_config) { | 3150 | switch (board_config) { |
3082 | default: | 3151 | default: |
3083 | case CXT5066_LAPTOP: | 3152 | case CXT5066_LAPTOP: |
@@ -3195,7 +3264,45 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3195 | * Automatic parser for CX20641 & co | 3264 | * Automatic parser for CX20641 & co |
3196 | */ | 3265 | */ |
3197 | 3266 | ||
3198 | static hda_nid_t cx_auto_adc_nids[] = { 0x14 }; | 3267 | static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo, |
3268 | struct hda_codec *codec, | ||
3269 | unsigned int stream_tag, | ||
3270 | unsigned int format, | ||
3271 | struct snd_pcm_substream *substream) | ||
3272 | { | ||
3273 | struct conexant_spec *spec = codec->spec; | ||
3274 | hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc; | ||
3275 | if (spec->adc_switching) { | ||
3276 | spec->cur_adc = adc; | ||
3277 | spec->cur_adc_stream_tag = stream_tag; | ||
3278 | spec->cur_adc_format = format; | ||
3279 | } | ||
3280 | snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); | ||
3281 | return 0; | ||
3282 | } | ||
3283 | |||
3284 | static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
3285 | struct hda_codec *codec, | ||
3286 | struct snd_pcm_substream *substream) | ||
3287 | { | ||
3288 | struct conexant_spec *spec = codec->spec; | ||
3289 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
3290 | spec->cur_adc = 0; | ||
3291 | return 0; | ||
3292 | } | ||
3293 | |||
3294 | static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { | ||
3295 | .substreams = 1, | ||
3296 | .channels_min = 2, | ||
3297 | .channels_max = 2, | ||
3298 | .nid = 0, /* fill later */ | ||
3299 | .ops = { | ||
3300 | .prepare = cx_auto_capture_pcm_prepare, | ||
3301 | .cleanup = cx_auto_capture_pcm_cleanup | ||
3302 | }, | ||
3303 | }; | ||
3304 | |||
3305 | static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; | ||
3199 | 3306 | ||
3200 | /* get the connection index of @nid in the widget @mux */ | 3307 | /* get the connection index of @nid in the widget @mux */ |
3201 | static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, | 3308 | static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, |
@@ -3320,61 +3427,339 @@ static void cx_auto_parse_output(struct hda_codec *codec) | |||
3320 | spec->multiout.dac_nids = spec->private_dac_nids; | 3427 | spec->multiout.dac_nids = spec->private_dac_nids; |
3321 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 3428 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
3322 | 3429 | ||
3323 | if (cfg->hp_outs > 0) | 3430 | for (i = 0; i < cfg->hp_outs; i++) { |
3324 | spec->auto_mute = 1; | 3431 | if (is_jack_detectable(codec, cfg->hp_pins[i])) { |
3432 | spec->auto_mute = 1; | ||
3433 | break; | ||
3434 | } | ||
3435 | } | ||
3436 | if (spec->auto_mute && cfg->line_out_pins[0] && | ||
3437 | cfg->line_out_pins[0] != cfg->hp_pins[0] && | ||
3438 | cfg->line_out_pins[0] != cfg->speaker_pins[0]) { | ||
3439 | for (i = 0; i < cfg->line_outs; i++) { | ||
3440 | if (is_jack_detectable(codec, cfg->line_out_pins[i])) { | ||
3441 | spec->detect_line = 1; | ||
3442 | break; | ||
3443 | } | ||
3444 | } | ||
3445 | spec->automute_lines = spec->detect_line; | ||
3446 | } | ||
3447 | |||
3325 | spec->vmaster_nid = spec->private_dac_nids[0]; | 3448 | spec->vmaster_nid = spec->private_dac_nids[0]; |
3326 | } | 3449 | } |
3327 | 3450 | ||
3451 | static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, | ||
3452 | hda_nid_t *pins, bool on); | ||
3453 | |||
3454 | static void do_automute(struct hda_codec *codec, int num_pins, | ||
3455 | hda_nid_t *pins, bool on) | ||
3456 | { | ||
3457 | int i; | ||
3458 | for (i = 0; i < num_pins; i++) | ||
3459 | snd_hda_codec_write(codec, pins[i], 0, | ||
3460 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3461 | on ? PIN_OUT : 0); | ||
3462 | cx_auto_turn_eapd(codec, num_pins, pins, on); | ||
3463 | } | ||
3464 | |||
3465 | static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | ||
3466 | { | ||
3467 | int i, present = 0; | ||
3468 | |||
3469 | for (i = 0; i < num_pins; i++) { | ||
3470 | hda_nid_t nid = pins[i]; | ||
3471 | if (!nid || !is_jack_detectable(codec, nid)) | ||
3472 | break; | ||
3473 | snd_hda_input_jack_report(codec, nid); | ||
3474 | present |= snd_hda_jack_detect(codec, nid); | ||
3475 | } | ||
3476 | return present; | ||
3477 | } | ||
3478 | |||
3328 | /* auto-mute/unmute speaker and line outs according to headphone jack */ | 3479 | /* auto-mute/unmute speaker and line outs according to headphone jack */ |
3480 | static void cx_auto_update_speakers(struct hda_codec *codec) | ||
3481 | { | ||
3482 | struct conexant_spec *spec = codec->spec; | ||
3483 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3484 | int on; | ||
3485 | |||
3486 | if (!spec->auto_mute) | ||
3487 | on = 0; | ||
3488 | else | ||
3489 | on = spec->hp_present | spec->line_present; | ||
3490 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); | ||
3491 | do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, !on); | ||
3492 | |||
3493 | /* toggle line-out mutes if needed, too */ | ||
3494 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ | ||
3495 | if (cfg->line_out_pins[0] == cfg->hp_pins[0] || | ||
3496 | cfg->line_out_pins[0] == cfg->speaker_pins[0]) | ||
3497 | return; | ||
3498 | if (!spec->automute_lines || !spec->auto_mute) | ||
3499 | on = 0; | ||
3500 | else | ||
3501 | on = spec->hp_present; | ||
3502 | do_automute(codec, cfg->line_outs, cfg->line_out_pins, !on); | ||
3503 | } | ||
3504 | |||
3329 | static void cx_auto_hp_automute(struct hda_codec *codec) | 3505 | static void cx_auto_hp_automute(struct hda_codec *codec) |
3330 | { | 3506 | { |
3331 | struct conexant_spec *spec = codec->spec; | 3507 | struct conexant_spec *spec = codec->spec; |
3332 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3508 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3333 | int i, present; | ||
3334 | 3509 | ||
3335 | if (!spec->auto_mute) | 3510 | if (!spec->auto_mute) |
3336 | return; | 3511 | return; |
3337 | present = 0; | 3512 | spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); |
3338 | for (i = 0; i < cfg->hp_outs; i++) { | 3513 | cx_auto_update_speakers(codec); |
3339 | if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) { | 3514 | } |
3340 | present = 1; | 3515 | |
3341 | break; | 3516 | static void cx_auto_line_automute(struct hda_codec *codec) |
3342 | } | 3517 | { |
3518 | struct conexant_spec *spec = codec->spec; | ||
3519 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3520 | |||
3521 | if (!spec->auto_mute || !spec->detect_line) | ||
3522 | return; | ||
3523 | spec->line_present = detect_jacks(codec, cfg->line_outs, | ||
3524 | cfg->line_out_pins); | ||
3525 | cx_auto_update_speakers(codec); | ||
3526 | } | ||
3527 | |||
3528 | static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, | ||
3529 | struct snd_ctl_elem_info *uinfo) | ||
3530 | { | ||
3531 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3532 | struct conexant_spec *spec = codec->spec; | ||
3533 | static const char * const texts2[] = { | ||
3534 | "Disabled", "Enabled" | ||
3535 | }; | ||
3536 | static const char * const texts3[] = { | ||
3537 | "Disabled", "Speaker Only", "Line-Out+Speaker" | ||
3538 | }; | ||
3539 | const char * const *texts; | ||
3540 | |||
3541 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
3542 | uinfo->count = 1; | ||
3543 | if (spec->automute_hp_lo) { | ||
3544 | uinfo->value.enumerated.items = 3; | ||
3545 | texts = texts3; | ||
3546 | } else { | ||
3547 | uinfo->value.enumerated.items = 2; | ||
3548 | texts = texts2; | ||
3343 | } | 3549 | } |
3344 | for (i = 0; i < cfg->line_outs; i++) { | 3550 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) |
3345 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | 3551 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; |
3346 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 3552 | strcpy(uinfo->value.enumerated.name, |
3347 | present ? 0 : PIN_OUT); | 3553 | texts[uinfo->value.enumerated.item]); |
3554 | return 0; | ||
3555 | } | ||
3556 | |||
3557 | static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, | ||
3558 | struct snd_ctl_elem_value *ucontrol) | ||
3559 | { | ||
3560 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3561 | struct conexant_spec *spec = codec->spec; | ||
3562 | unsigned int val; | ||
3563 | if (!spec->auto_mute) | ||
3564 | val = 0; | ||
3565 | else if (!spec->automute_lines) | ||
3566 | val = 1; | ||
3567 | else | ||
3568 | val = 2; | ||
3569 | ucontrol->value.enumerated.item[0] = val; | ||
3570 | return 0; | ||
3571 | } | ||
3572 | |||
3573 | static int cx_automute_mode_put(struct snd_kcontrol *kcontrol, | ||
3574 | struct snd_ctl_elem_value *ucontrol) | ||
3575 | { | ||
3576 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3577 | struct conexant_spec *spec = codec->spec; | ||
3578 | |||
3579 | switch (ucontrol->value.enumerated.item[0]) { | ||
3580 | case 0: | ||
3581 | if (!spec->auto_mute) | ||
3582 | return 0; | ||
3583 | spec->auto_mute = 0; | ||
3584 | break; | ||
3585 | case 1: | ||
3586 | if (spec->auto_mute && !spec->automute_lines) | ||
3587 | return 0; | ||
3588 | spec->auto_mute = 1; | ||
3589 | spec->automute_lines = 0; | ||
3590 | break; | ||
3591 | case 2: | ||
3592 | if (!spec->automute_hp_lo) | ||
3593 | return -EINVAL; | ||
3594 | if (spec->auto_mute && spec->automute_lines) | ||
3595 | return 0; | ||
3596 | spec->auto_mute = 1; | ||
3597 | spec->automute_lines = 1; | ||
3598 | break; | ||
3599 | default: | ||
3600 | return -EINVAL; | ||
3348 | } | 3601 | } |
3349 | for (i = 0; !present && i < cfg->line_outs; i++) | 3602 | cx_auto_update_speakers(codec); |
3350 | if (snd_hda_jack_detect(codec, cfg->line_out_pins[i])) | 3603 | return 1; |
3351 | present = 1; | 3604 | } |
3352 | for (i = 0; i < cfg->speaker_outs; i++) { | 3605 | |
3353 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | 3606 | static const struct snd_kcontrol_new cx_automute_mode_enum[] = { |
3354 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 3607 | { |
3355 | present ? 0 : PIN_OUT); | 3608 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3609 | .name = "Auto-Mute Mode", | ||
3610 | .info = cx_automute_mode_info, | ||
3611 | .get = cx_automute_mode_get, | ||
3612 | .put = cx_automute_mode_put, | ||
3613 | }, | ||
3614 | { } | ||
3615 | }; | ||
3616 | |||
3617 | static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
3618 | struct snd_ctl_elem_info *uinfo) | ||
3619 | { | ||
3620 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3621 | struct conexant_spec *spec = codec->spec; | ||
3622 | |||
3623 | return snd_hda_input_mux_info(&spec->private_imux, uinfo); | ||
3624 | } | ||
3625 | |||
3626 | static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
3627 | struct snd_ctl_elem_value *ucontrol) | ||
3628 | { | ||
3629 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3630 | struct conexant_spec *spec = codec->spec; | ||
3631 | |||
3632 | ucontrol->value.enumerated.item[0] = spec->cur_mux[0]; | ||
3633 | return 0; | ||
3634 | } | ||
3635 | |||
3636 | /* look for the route the given pin from mux and return the index; | ||
3637 | * if do_select is set, actually select the route. | ||
3638 | */ | ||
3639 | static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux, | ||
3640 | hda_nid_t pin, hda_nid_t *srcp, | ||
3641 | bool do_select, int depth) | ||
3642 | { | ||
3643 | hda_nid_t conn[HDA_MAX_NUM_INPUTS]; | ||
3644 | int i, nums; | ||
3645 | |||
3646 | switch (get_wcaps_type(get_wcaps(codec, mux))) { | ||
3647 | case AC_WID_AUD_IN: | ||
3648 | case AC_WID_AUD_SEL: | ||
3649 | case AC_WID_AUD_MIX: | ||
3650 | break; | ||
3651 | default: | ||
3652 | return -1; | ||
3356 | } | 3653 | } |
3654 | |||
3655 | nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); | ||
3656 | for (i = 0; i < nums; i++) | ||
3657 | if (conn[i] == pin) { | ||
3658 | if (do_select) | ||
3659 | snd_hda_codec_write(codec, mux, 0, | ||
3660 | AC_VERB_SET_CONNECT_SEL, i); | ||
3661 | if (srcp) | ||
3662 | *srcp = mux; | ||
3663 | return i; | ||
3664 | } | ||
3665 | depth++; | ||
3666 | if (depth == 2) | ||
3667 | return -1; | ||
3668 | for (i = 0; i < nums; i++) { | ||
3669 | int ret = __select_input_connection(codec, conn[i], pin, srcp, | ||
3670 | do_select, depth); | ||
3671 | if (ret >= 0) { | ||
3672 | if (do_select) | ||
3673 | snd_hda_codec_write(codec, mux, 0, | ||
3674 | AC_VERB_SET_CONNECT_SEL, i); | ||
3675 | return i; | ||
3676 | } | ||
3677 | } | ||
3678 | return -1; | ||
3679 | } | ||
3680 | |||
3681 | static void select_input_connection(struct hda_codec *codec, hda_nid_t mux, | ||
3682 | hda_nid_t pin) | ||
3683 | { | ||
3684 | __select_input_connection(codec, mux, pin, NULL, true, 0); | ||
3685 | } | ||
3686 | |||
3687 | static int get_input_connection(struct hda_codec *codec, hda_nid_t mux, | ||
3688 | hda_nid_t pin) | ||
3689 | { | ||
3690 | return __select_input_connection(codec, mux, pin, NULL, false, 0); | ||
3691 | } | ||
3692 | |||
3693 | static int cx_auto_mux_enum_update(struct hda_codec *codec, | ||
3694 | const struct hda_input_mux *imux, | ||
3695 | unsigned int idx) | ||
3696 | { | ||
3697 | struct conexant_spec *spec = codec->spec; | ||
3698 | hda_nid_t adc; | ||
3699 | |||
3700 | if (!imux->num_items) | ||
3701 | return 0; | ||
3702 | if (idx >= imux->num_items) | ||
3703 | idx = imux->num_items - 1; | ||
3704 | if (spec->cur_mux[0] == idx) | ||
3705 | return 0; | ||
3706 | adc = spec->imux_info[idx].adc; | ||
3707 | select_input_connection(codec, spec->imux_info[idx].adc, | ||
3708 | spec->imux_info[idx].pin); | ||
3709 | if (spec->cur_adc && spec->cur_adc != adc) { | ||
3710 | /* stream is running, let's swap the current ADC */ | ||
3711 | __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); | ||
3712 | spec->cur_adc = adc; | ||
3713 | snd_hda_codec_setup_stream(codec, adc, | ||
3714 | spec->cur_adc_stream_tag, 0, | ||
3715 | spec->cur_adc_format); | ||
3716 | } | ||
3717 | spec->cur_mux[0] = idx; | ||
3718 | return 1; | ||
3719 | } | ||
3720 | |||
3721 | static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
3722 | struct snd_ctl_elem_value *ucontrol) | ||
3723 | { | ||
3724 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3725 | struct conexant_spec *spec = codec->spec; | ||
3726 | |||
3727 | return cx_auto_mux_enum_update(codec, &spec->private_imux, | ||
3728 | ucontrol->value.enumerated.item[0]); | ||
3729 | } | ||
3730 | |||
3731 | static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { | ||
3732 | { | ||
3733 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3734 | .name = "Capture Source", | ||
3735 | .info = cx_auto_mux_enum_info, | ||
3736 | .get = cx_auto_mux_enum_get, | ||
3737 | .put = cx_auto_mux_enum_put | ||
3738 | }, | ||
3739 | {} | ||
3740 | }; | ||
3741 | |||
3742 | static bool select_automic(struct hda_codec *codec, int idx, bool detect) | ||
3743 | { | ||
3744 | struct conexant_spec *spec = codec->spec; | ||
3745 | if (idx < 0) | ||
3746 | return false; | ||
3747 | if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) | ||
3748 | return false; | ||
3749 | cx_auto_mux_enum_update(codec, &spec->private_imux, idx); | ||
3750 | return true; | ||
3357 | } | 3751 | } |
3358 | 3752 | ||
3359 | /* automatic switch internal and external mic */ | 3753 | /* automatic switch internal and external mic */ |
3360 | static void cx_auto_automic(struct hda_codec *codec) | 3754 | static void cx_auto_automic(struct hda_codec *codec) |
3361 | { | 3755 | { |
3362 | struct conexant_spec *spec = codec->spec; | 3756 | struct conexant_spec *spec = codec->spec; |
3363 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3364 | struct hda_input_mux *imux = &spec->private_imux; | ||
3365 | int ext_idx = spec->auto_mic_ext; | ||
3366 | 3757 | ||
3367 | if (!spec->auto_mic) | 3758 | if (!spec->auto_mic) |
3368 | return; | 3759 | return; |
3369 | if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { | 3760 | if (!select_automic(codec, spec->auto_mic_ext, true)) |
3370 | snd_hda_codec_write(codec, spec->adc_nids[0], 0, | 3761 | if (!select_automic(codec, spec->auto_mic_dock, true)) |
3371 | AC_VERB_SET_CONNECT_SEL, | 3762 | select_automic(codec, spec->auto_mic_int, false); |
3372 | imux->items[ext_idx].index); | ||
3373 | } else { | ||
3374 | snd_hda_codec_write(codec, spec->adc_nids[0], 0, | ||
3375 | AC_VERB_SET_CONNECT_SEL, | ||
3376 | imux->items[!ext_idx].index); | ||
3377 | } | ||
3378 | } | 3763 | } |
3379 | 3764 | ||
3380 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | 3765 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -3383,7 +3768,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | |||
3383 | switch (res >> 26) { | 3768 | switch (res >> 26) { |
3384 | case CONEXANT_HP_EVENT: | 3769 | case CONEXANT_HP_EVENT: |
3385 | cx_auto_hp_automute(codec); | 3770 | cx_auto_hp_automute(codec); |
3386 | snd_hda_input_jack_report(codec, nid); | 3771 | break; |
3772 | case CONEXANT_LINE_EVENT: | ||
3773 | cx_auto_line_automute(codec); | ||
3387 | break; | 3774 | break; |
3388 | case CONEXANT_MIC_EVENT: | 3775 | case CONEXANT_MIC_EVENT: |
3389 | cx_auto_automic(codec); | 3776 | cx_auto_automic(codec); |
@@ -3392,43 +3779,45 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | |||
3392 | } | 3779 | } |
3393 | } | 3780 | } |
3394 | 3781 | ||
3395 | /* return true if it's an internal-mic pin */ | ||
3396 | static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) | ||
3397 | { | ||
3398 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3399 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | ||
3400 | snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT; | ||
3401 | } | ||
3402 | |||
3403 | /* return true if it's an external-mic pin */ | ||
3404 | static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) | ||
3405 | { | ||
3406 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3407 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | ||
3408 | snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && | ||
3409 | (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT); | ||
3410 | } | ||
3411 | |||
3412 | /* check whether the pin config is suitable for auto-mic switching; | 3782 | /* check whether the pin config is suitable for auto-mic switching; |
3413 | * auto-mic is enabled only when one int-mic and one-ext mic exist | 3783 | * auto-mic is enabled only when one int-mic and one ext- and/or |
3784 | * one dock-mic exist | ||
3414 | */ | 3785 | */ |
3415 | static void cx_auto_check_auto_mic(struct hda_codec *codec) | 3786 | static void cx_auto_check_auto_mic(struct hda_codec *codec) |
3416 | { | 3787 | { |
3417 | struct conexant_spec *spec = codec->spec; | 3788 | struct conexant_spec *spec = codec->spec; |
3418 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3789 | int pset[INPUT_PIN_ATTR_NORMAL + 1]; |
3790 | int i; | ||
3419 | 3791 | ||
3420 | if (is_ext_mic(codec, cfg->inputs[0].pin) && | 3792 | for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++) |
3421 | is_int_mic(codec, cfg->inputs[1].pin)) { | 3793 | pset[i] = -1; |
3422 | spec->auto_mic = 1; | 3794 | for (i = 0; i < spec->private_imux.num_items; i++) { |
3423 | spec->auto_mic_ext = 1; | 3795 | hda_nid_t pin = spec->imux_info[i].pin; |
3424 | return; | 3796 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); |
3425 | } | 3797 | int type, attr; |
3426 | if (is_int_mic(codec, cfg->inputs[1].pin) && | 3798 | attr = snd_hda_get_input_pin_attr(def_conf); |
3427 | is_ext_mic(codec, cfg->inputs[0].pin)) { | 3799 | if (attr == INPUT_PIN_ATTR_UNUSED) |
3428 | spec->auto_mic = 1; | 3800 | return; /* invalid entry */ |
3429 | spec->auto_mic_ext = 0; | 3801 | if (attr > INPUT_PIN_ATTR_NORMAL) |
3430 | return; | 3802 | attr = INPUT_PIN_ATTR_NORMAL; |
3803 | if (attr != INPUT_PIN_ATTR_INT && | ||
3804 | !is_jack_detectable(codec, pin)) | ||
3805 | return; /* non-detectable pin */ | ||
3806 | type = get_defcfg_device(def_conf); | ||
3807 | if (type != AC_JACK_MIC_IN && | ||
3808 | (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN)) | ||
3809 | return; /* no valid input type */ | ||
3810 | if (pset[attr] >= 0) | ||
3811 | return; /* already occupied */ | ||
3812 | pset[attr] = i; | ||
3431 | } | 3813 | } |
3814 | if (pset[INPUT_PIN_ATTR_INT] < 0 || | ||
3815 | (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) | ||
3816 | return; /* no input to switch*/ | ||
3817 | spec->auto_mic = 1; | ||
3818 | spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; | ||
3819 | spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; | ||
3820 | spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; | ||
3432 | } | 3821 | } |
3433 | 3822 | ||
3434 | static void cx_auto_parse_input(struct hda_codec *codec) | 3823 | static void cx_auto_parse_input(struct hda_codec *codec) |
@@ -3436,22 +3825,37 @@ static void cx_auto_parse_input(struct hda_codec *codec) | |||
3436 | struct conexant_spec *spec = codec->spec; | 3825 | struct conexant_spec *spec = codec->spec; |
3437 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3826 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3438 | struct hda_input_mux *imux; | 3827 | struct hda_input_mux *imux; |
3439 | int i; | 3828 | int i, j; |
3440 | 3829 | ||
3441 | imux = &spec->private_imux; | 3830 | imux = &spec->private_imux; |
3442 | for (i = 0; i < cfg->num_inputs; i++) { | 3831 | for (i = 0; i < cfg->num_inputs; i++) { |
3443 | int idx = get_connection_index(codec, spec->adc_nids[0], | 3832 | for (j = 0; j < spec->num_adc_nids; j++) { |
3444 | cfg->inputs[i].pin); | 3833 | hda_nid_t adc = spec->adc_nids[j]; |
3445 | if (idx >= 0) { | 3834 | int idx = get_input_connection(codec, adc, |
3446 | const char *label; | 3835 | cfg->inputs[i].pin); |
3447 | label = hda_get_autocfg_input_label(codec, cfg, i); | 3836 | if (idx >= 0) { |
3448 | snd_hda_add_imux_item(imux, label, idx, NULL); | 3837 | const char *label; |
3838 | label = hda_get_autocfg_input_label(codec, cfg, i); | ||
3839 | spec->imux_info[imux->num_items].index = i; | ||
3840 | spec->imux_info[imux->num_items].boost = 0; | ||
3841 | spec->imux_info[imux->num_items].adc = adc; | ||
3842 | spec->imux_info[imux->num_items].pin = | ||
3843 | cfg->inputs[i].pin; | ||
3844 | snd_hda_add_imux_item(imux, label, idx, NULL); | ||
3845 | break; | ||
3846 | } | ||
3449 | } | 3847 | } |
3450 | } | 3848 | } |
3451 | if (imux->num_items == 2 && cfg->num_inputs == 2) | 3849 | if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) |
3452 | cx_auto_check_auto_mic(codec); | 3850 | cx_auto_check_auto_mic(codec); |
3453 | if (imux->num_items > 1 && !spec->auto_mic) | 3851 | if (imux->num_items > 1 && !spec->auto_mic) { |
3454 | spec->input_mux = imux; | 3852 | for (i = 1; i < imux->num_items; i++) { |
3853 | if (spec->imux_info[i].adc != spec->imux_info[0].adc) { | ||
3854 | spec->adc_switching = 1; | ||
3855 | break; | ||
3856 | } | ||
3857 | } | ||
3858 | } | ||
3455 | } | 3859 | } |
3456 | 3860 | ||
3457 | /* get digital-input audio widget corresponding to the given pin */ | 3861 | /* get digital-input audio widget corresponding to the given pin */ |
@@ -3517,14 +3921,15 @@ static int cx_auto_parse_auto_config(struct hda_codec *codec) | |||
3517 | return 0; | 3921 | return 0; |
3518 | } | 3922 | } |
3519 | 3923 | ||
3520 | static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins, | 3924 | static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, |
3521 | hda_nid_t *pins) | 3925 | hda_nid_t *pins, bool on) |
3522 | { | 3926 | { |
3523 | int i; | 3927 | int i; |
3524 | for (i = 0; i < num_pins; i++) { | 3928 | for (i = 0; i < num_pins; i++) { |
3525 | if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) | 3929 | if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) |
3526 | snd_hda_codec_write(codec, pins[i], 0, | 3930 | snd_hda_codec_write(codec, pins[i], 0, |
3527 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | 3931 | AC_VERB_SET_EAPD_BTLENABLE, |
3932 | on ? 0x02 : 0); | ||
3528 | } | 3933 | } |
3529 | } | 3934 | } |
3530 | 3935 | ||
@@ -3537,6 +3942,34 @@ static void select_connection(struct hda_codec *codec, hda_nid_t pin, | |||
3537 | AC_VERB_SET_CONNECT_SEL, idx); | 3942 | AC_VERB_SET_CONNECT_SEL, idx); |
3538 | } | 3943 | } |
3539 | 3944 | ||
3945 | static void mute_outputs(struct hda_codec *codec, int num_nids, | ||
3946 | const hda_nid_t *nids) | ||
3947 | { | ||
3948 | int i, val; | ||
3949 | |||
3950 | for (i = 0; i < num_nids; i++) { | ||
3951 | hda_nid_t nid = nids[i]; | ||
3952 | if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) | ||
3953 | continue; | ||
3954 | if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE) | ||
3955 | val = AMP_OUT_MUTE; | ||
3956 | else | ||
3957 | val = AMP_OUT_ZERO; | ||
3958 | snd_hda_codec_write(codec, nid, 0, | ||
3959 | AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
3960 | } | ||
3961 | } | ||
3962 | |||
3963 | static void enable_unsol_pins(struct hda_codec *codec, int num_pins, | ||
3964 | hda_nid_t *pins, unsigned int tag) | ||
3965 | { | ||
3966 | int i; | ||
3967 | for (i = 0; i < num_pins; i++) | ||
3968 | snd_hda_codec_write(codec, pins[i], 0, | ||
3969 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3970 | AC_USRSP_EN | tag); | ||
3971 | } | ||
3972 | |||
3540 | static void cx_auto_init_output(struct hda_codec *codec) | 3973 | static void cx_auto_init_output(struct hda_codec *codec) |
3541 | { | 3974 | { |
3542 | struct conexant_spec *spec = codec->spec; | 3975 | struct conexant_spec *spec = codec->spec; |
@@ -3544,51 +3977,53 @@ static void cx_auto_init_output(struct hda_codec *codec) | |||
3544 | hda_nid_t nid; | 3977 | hda_nid_t nid; |
3545 | int i; | 3978 | int i; |
3546 | 3979 | ||
3547 | for (i = 0; i < spec->multiout.num_dacs; i++) | 3980 | mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids); |
3548 | snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, | ||
3549 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
3550 | |||
3551 | for (i = 0; i < cfg->hp_outs; i++) | 3981 | for (i = 0; i < cfg->hp_outs; i++) |
3552 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | 3982 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, |
3553 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | 3983 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); |
3554 | if (spec->auto_mute) { | 3984 | mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); |
3555 | for (i = 0; i < cfg->hp_outs; i++) { | 3985 | mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); |
3556 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | 3986 | mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); |
3557 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3558 | AC_USRSP_EN | CONEXANT_HP_EVENT); | ||
3559 | } | ||
3560 | cx_auto_hp_automute(codec); | ||
3561 | } else { | ||
3562 | for (i = 0; i < cfg->line_outs; i++) | ||
3563 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | ||
3564 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
3565 | for (i = 0; i < cfg->speaker_outs; i++) | ||
3566 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | ||
3567 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
3568 | } | ||
3569 | |||
3570 | for (i = 0; i < spec->dac_info_filled; i++) { | 3987 | for (i = 0; i < spec->dac_info_filled; i++) { |
3571 | nid = spec->dac_info[i].dac; | 3988 | nid = spec->dac_info[i].dac; |
3572 | if (!nid) | 3989 | if (!nid) |
3573 | nid = spec->multiout.dac_nids[0]; | 3990 | nid = spec->multiout.dac_nids[0]; |
3574 | select_connection(codec, spec->dac_info[i].pin, nid); | 3991 | select_connection(codec, spec->dac_info[i].pin, nid); |
3575 | } | 3992 | } |
3576 | 3993 | if (spec->auto_mute) { | |
3577 | /* turn on EAPD */ | 3994 | enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, |
3578 | cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins); | 3995 | CONEXANT_HP_EVENT); |
3579 | cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins); | 3996 | spec->hp_present = detect_jacks(codec, cfg->hp_outs, |
3580 | cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins); | 3997 | cfg->hp_pins); |
3998 | if (spec->detect_line) { | ||
3999 | enable_unsol_pins(codec, cfg->line_outs, | ||
4000 | cfg->line_out_pins, | ||
4001 | CONEXANT_LINE_EVENT); | ||
4002 | spec->line_present = | ||
4003 | detect_jacks(codec, cfg->line_outs, | ||
4004 | cfg->line_out_pins); | ||
4005 | } | ||
4006 | } | ||
4007 | cx_auto_update_speakers(codec); | ||
3581 | } | 4008 | } |
3582 | 4009 | ||
3583 | static void cx_auto_init_input(struct hda_codec *codec) | 4010 | static void cx_auto_init_input(struct hda_codec *codec) |
3584 | { | 4011 | { |
3585 | struct conexant_spec *spec = codec->spec; | 4012 | struct conexant_spec *spec = codec->spec; |
3586 | struct auto_pin_cfg *cfg = &spec->autocfg; | 4013 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3587 | int i; | 4014 | int i, val; |
3588 | 4015 | ||
3589 | for (i = 0; i < spec->num_adc_nids; i++) | 4016 | for (i = 0; i < spec->num_adc_nids; i++) { |
3590 | snd_hda_codec_write(codec, spec->adc_nids[i], 0, | 4017 | hda_nid_t nid = spec->adc_nids[i]; |
3591 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)); | 4018 | if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) |
4019 | continue; | ||
4020 | if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) | ||
4021 | val = AMP_IN_MUTE(0); | ||
4022 | else | ||
4023 | val = AMP_IN_UNMUTE(0); | ||
4024 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
4025 | val); | ||
4026 | } | ||
3592 | 4027 | ||
3593 | for (i = 0; i < cfg->num_inputs; i++) { | 4028 | for (i = 0; i < cfg->num_inputs; i++) { |
3594 | unsigned int type; | 4029 | unsigned int type; |
@@ -3601,17 +4036,22 @@ static void cx_auto_init_input(struct hda_codec *codec) | |||
3601 | } | 4036 | } |
3602 | 4037 | ||
3603 | if (spec->auto_mic) { | 4038 | if (spec->auto_mic) { |
3604 | int ext_idx = spec->auto_mic_ext; | 4039 | if (spec->auto_mic_ext >= 0) { |
3605 | snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, | 4040 | snd_hda_codec_write(codec, |
3606 | AC_VERB_SET_UNSOLICITED_ENABLE, | 4041 | cfg->inputs[spec->auto_mic_ext].pin, 0, |
3607 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | 4042 | AC_VERB_SET_UNSOLICITED_ENABLE, |
4043 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
4044 | } | ||
4045 | if (spec->auto_mic_dock >= 0) { | ||
4046 | snd_hda_codec_write(codec, | ||
4047 | cfg->inputs[spec->auto_mic_dock].pin, 0, | ||
4048 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4049 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
4050 | } | ||
3608 | cx_auto_automic(codec); | 4051 | cx_auto_automic(codec); |
3609 | } else { | 4052 | } else { |
3610 | for (i = 0; i < spec->num_adc_nids; i++) { | 4053 | select_input_connection(codec, spec->imux_info[0].adc, |
3611 | snd_hda_codec_write(codec, spec->adc_nids[i], 0, | 4054 | spec->imux_info[0].pin); |
3612 | AC_VERB_SET_CONNECT_SEL, | ||
3613 | spec->private_imux.items[0].index); | ||
3614 | } | ||
3615 | } | 4055 | } |
3616 | } | 4056 | } |
3617 | 4057 | ||
@@ -3646,7 +4086,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, | |||
3646 | HDA_CODEC_VOLUME(name, 0, 0, 0), | 4086 | HDA_CODEC_VOLUME(name, 0, 0, 0), |
3647 | HDA_CODEC_MUTE(name, 0, 0, 0), | 4087 | HDA_CODEC_MUTE(name, 0, 0, 0), |
3648 | }; | 4088 | }; |
3649 | static char *sfx[2] = { "Volume", "Switch" }; | 4089 | static const char * const sfx[2] = { "Volume", "Switch" }; |
3650 | int i, err; | 4090 | int i, err; |
3651 | 4091 | ||
3652 | for (i = 0; i < 2; i++) { | 4092 | for (i = 0; i < 2; i++) { |
@@ -3674,6 +4114,19 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, | |||
3674 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ | 4114 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ |
3675 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) | 4115 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) |
3676 | 4116 | ||
4117 | static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, | ||
4118 | hda_nid_t pin, const char *name, int idx) | ||
4119 | { | ||
4120 | unsigned int caps; | ||
4121 | caps = query_amp_caps(codec, dac, HDA_OUTPUT); | ||
4122 | if (caps & AC_AMPCAP_NUM_STEPS) | ||
4123 | return cx_auto_add_pb_volume(codec, dac, name, idx); | ||
4124 | caps = query_amp_caps(codec, pin, HDA_OUTPUT); | ||
4125 | if (caps & AC_AMPCAP_NUM_STEPS) | ||
4126 | return cx_auto_add_pb_volume(codec, pin, name, idx); | ||
4127 | return 0; | ||
4128 | } | ||
4129 | |||
3677 | static int cx_auto_build_output_controls(struct hda_codec *codec) | 4130 | static int cx_auto_build_output_controls(struct hda_codec *codec) |
3678 | { | 4131 | { |
3679 | struct conexant_spec *spec = codec->spec; | 4132 | struct conexant_spec *spec = codec->spec; |
@@ -3682,8 +4135,10 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
3682 | static const char * const texts[3] = { "Front", "Surround", "CLFE" }; | 4135 | static const char * const texts[3] = { "Front", "Surround", "CLFE" }; |
3683 | 4136 | ||
3684 | if (spec->dac_info_filled == 1) | 4137 | if (spec->dac_info_filled == 1) |
3685 | return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, | 4138 | return try_add_pb_volume(codec, spec->dac_info[0].dac, |
3686 | "Master", 0); | 4139 | spec->dac_info[0].pin, |
4140 | "Master", 0); | ||
4141 | |||
3687 | for (i = 0; i < spec->dac_info_filled; i++) { | 4142 | for (i = 0; i < spec->dac_info_filled; i++) { |
3688 | const char *label; | 4143 | const char *label; |
3689 | int idx, type; | 4144 | int idx, type; |
@@ -3707,74 +4162,123 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
3707 | idx = num_spk++; | 4162 | idx = num_spk++; |
3708 | break; | 4163 | break; |
3709 | } | 4164 | } |
3710 | err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac, | 4165 | err = try_add_pb_volume(codec, spec->dac_info[i].dac, |
3711 | label, idx); | 4166 | spec->dac_info[i].pin, |
4167 | label, idx); | ||
4168 | if (err < 0) | ||
4169 | return err; | ||
4170 | } | ||
4171 | |||
4172 | if (spec->auto_mute) { | ||
4173 | err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); | ||
3712 | if (err < 0) | 4174 | if (err < 0) |
3713 | return err; | 4175 | return err; |
3714 | } | 4176 | } |
4177 | |||
4178 | return 0; | ||
4179 | } | ||
4180 | |||
4181 | static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, | ||
4182 | const char *label, const char *pfx, | ||
4183 | int cidx) | ||
4184 | { | ||
4185 | struct conexant_spec *spec = codec->spec; | ||
4186 | int i; | ||
4187 | |||
4188 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
4189 | hda_nid_t adc_nid = spec->adc_nids[i]; | ||
4190 | int idx = get_input_connection(codec, adc_nid, nid); | ||
4191 | if (idx < 0) | ||
4192 | continue; | ||
4193 | return cx_auto_add_volume_idx(codec, label, pfx, | ||
4194 | cidx, adc_nid, HDA_INPUT, idx); | ||
4195 | } | ||
4196 | return 0; | ||
4197 | } | ||
4198 | |||
4199 | static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, | ||
4200 | const char *label, int cidx) | ||
4201 | { | ||
4202 | struct conexant_spec *spec = codec->spec; | ||
4203 | hda_nid_t mux, nid; | ||
4204 | int i, con; | ||
4205 | |||
4206 | nid = spec->imux_info[idx].pin; | ||
4207 | if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) | ||
4208 | return cx_auto_add_volume(codec, label, " Boost", cidx, | ||
4209 | nid, HDA_INPUT); | ||
4210 | con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, | ||
4211 | &mux, false, 0); | ||
4212 | if (con < 0) | ||
4213 | return 0; | ||
4214 | for (i = 0; i < idx; i++) { | ||
4215 | if (spec->imux_info[i].boost == mux) | ||
4216 | return 0; /* already present */ | ||
4217 | } | ||
4218 | |||
4219 | if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) { | ||
4220 | spec->imux_info[idx].boost = mux; | ||
4221 | return cx_auto_add_volume(codec, label, " Boost", 0, | ||
4222 | mux, HDA_OUTPUT); | ||
4223 | } | ||
3715 | return 0; | 4224 | return 0; |
3716 | } | 4225 | } |
3717 | 4226 | ||
3718 | static int cx_auto_build_input_controls(struct hda_codec *codec) | 4227 | static int cx_auto_build_input_controls(struct hda_codec *codec) |
3719 | { | 4228 | { |
3720 | struct conexant_spec *spec = codec->spec; | 4229 | struct conexant_spec *spec = codec->spec; |
3721 | struct auto_pin_cfg *cfg = &spec->autocfg; | 4230 | struct hda_input_mux *imux = &spec->private_imux; |
3722 | static const char *prev_label; | 4231 | const char *prev_label; |
3723 | int i, err, cidx, conn_len; | 4232 | int input_conn[HDA_MAX_NUM_INPUTS]; |
3724 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | 4233 | int i, err, cidx; |
3725 | 4234 | int multi_connection; | |
3726 | int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ | 4235 | |
3727 | int adc_nid = spec->adc_nids[0]; | 4236 | multi_connection = 0; |
3728 | 4237 | for (i = 0; i < imux->num_items; i++) { | |
3729 | conn_len = snd_hda_get_connections(codec, adc_nid, conn, | 4238 | cidx = get_input_connection(codec, spec->imux_info[i].adc, |
3730 | HDA_MAX_CONNECTIONS); | 4239 | spec->imux_info[i].pin); |
3731 | if (conn_len < 0) | 4240 | input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; |
3732 | return conn_len; | 4241 | if (i > 0 && input_conn[i] != input_conn[0]) |
3733 | 4242 | multi_connection = 1; | |
3734 | multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; | ||
3735 | if (!multi_adc_volume) { | ||
3736 | err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, | ||
3737 | HDA_INPUT); | ||
3738 | if (err < 0) | ||
3739 | return err; | ||
3740 | } | 4243 | } |
3741 | 4244 | ||
3742 | prev_label = NULL; | 4245 | prev_label = NULL; |
3743 | cidx = 0; | 4246 | cidx = 0; |
3744 | for (i = 0; i < cfg->num_inputs; i++) { | 4247 | for (i = 0; i < imux->num_items; i++) { |
3745 | hda_nid_t nid = cfg->inputs[i].pin; | 4248 | hda_nid_t nid = spec->imux_info[i].pin; |
3746 | const char *label; | 4249 | const char *label; |
3747 | int j; | ||
3748 | int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; | ||
3749 | if (!pin_amp && !multi_adc_volume) | ||
3750 | continue; | ||
3751 | 4250 | ||
3752 | label = hda_get_autocfg_input_label(codec, cfg, i); | 4251 | label = hda_get_autocfg_input_label(codec, &spec->autocfg, |
4252 | spec->imux_info[i].index); | ||
3753 | if (label == prev_label) | 4253 | if (label == prev_label) |
3754 | cidx++; | 4254 | cidx++; |
3755 | else | 4255 | else |
3756 | cidx = 0; | 4256 | cidx = 0; |
3757 | prev_label = label; | 4257 | prev_label = label; |
3758 | 4258 | ||
3759 | if (pin_amp) { | 4259 | err = cx_auto_add_boost_volume(codec, i, label, cidx); |
3760 | err = cx_auto_add_volume(codec, label, " Boost", cidx, | 4260 | if (err < 0) |
3761 | nid, HDA_INPUT); | 4261 | return err; |
3762 | if (err < 0) | ||
3763 | return err; | ||
3764 | } | ||
3765 | 4262 | ||
3766 | if (!multi_adc_volume) | 4263 | if (!multi_connection) { |
3767 | continue; | 4264 | if (i > 0) |
3768 | for (j = 0; j < conn_len; j++) { | 4265 | continue; |
3769 | if (conn[j] == nid) { | 4266 | err = cx_auto_add_capture_volume(codec, nid, |
3770 | err = cx_auto_add_volume_idx(codec, label, | 4267 | "Capture", "", cidx); |
3771 | " Capture", cidx, adc_nid, HDA_INPUT, j); | 4268 | } else { |
3772 | if (err < 0) | 4269 | err = cx_auto_add_capture_volume(codec, nid, |
3773 | return err; | 4270 | label, " Capture", cidx); |
3774 | break; | ||
3775 | } | ||
3776 | } | 4271 | } |
4272 | if (err < 0) | ||
4273 | return err; | ||
3777 | } | 4274 | } |
4275 | |||
4276 | if (spec->private_imux.num_items > 1 && !spec->auto_mic) { | ||
4277 | err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); | ||
4278 | if (err < 0) | ||
4279 | return err; | ||
4280 | } | ||
4281 | |||
3778 | return 0; | 4282 | return 0; |
3779 | } | 4283 | } |
3780 | 4284 | ||
@@ -3791,7 +4295,29 @@ static int cx_auto_build_controls(struct hda_codec *codec) | |||
3791 | return conexant_build_controls(codec); | 4295 | return conexant_build_controls(codec); |
3792 | } | 4296 | } |
3793 | 4297 | ||
3794 | static struct hda_codec_ops cx_auto_patch_ops = { | 4298 | static int cx_auto_search_adcs(struct hda_codec *codec) |
4299 | { | ||
4300 | struct conexant_spec *spec = codec->spec; | ||
4301 | hda_nid_t nid, end_nid; | ||
4302 | |||
4303 | end_nid = codec->start_nid + codec->num_nodes; | ||
4304 | for (nid = codec->start_nid; nid < end_nid; nid++) { | ||
4305 | unsigned int caps = get_wcaps(codec, nid); | ||
4306 | if (get_wcaps_type(caps) != AC_WID_AUD_IN) | ||
4307 | continue; | ||
4308 | if (caps & AC_WCAP_DIGITAL) | ||
4309 | continue; | ||
4310 | if (snd_BUG_ON(spec->num_adc_nids >= | ||
4311 | ARRAY_SIZE(spec->private_adc_nids))) | ||
4312 | break; | ||
4313 | spec->private_adc_nids[spec->num_adc_nids++] = nid; | ||
4314 | } | ||
4315 | spec->adc_nids = spec->private_adc_nids; | ||
4316 | return 0; | ||
4317 | } | ||
4318 | |||
4319 | |||
4320 | static const struct hda_codec_ops cx_auto_patch_ops = { | ||
3795 | .build_controls = cx_auto_build_controls, | 4321 | .build_controls = cx_auto_build_controls, |
3796 | .build_pcms = conexant_build_pcms, | 4322 | .build_pcms = conexant_build_pcms, |
3797 | .init = cx_auto_init, | 4323 | .init = cx_auto_init, |
@@ -3808,19 +4334,24 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3808 | struct conexant_spec *spec; | 4334 | struct conexant_spec *spec; |
3809 | int err; | 4335 | int err; |
3810 | 4336 | ||
4337 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
4338 | codec->chip_name); | ||
4339 | |||
3811 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4340 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
3812 | if (!spec) | 4341 | if (!spec) |
3813 | return -ENOMEM; | 4342 | return -ENOMEM; |
3814 | codec->spec = spec; | 4343 | codec->spec = spec; |
3815 | spec->adc_nids = cx_auto_adc_nids; | 4344 | codec->pin_amp_workaround = 1; |
3816 | spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); | 4345 | err = cx_auto_search_adcs(codec); |
3817 | spec->capsrc_nids = spec->adc_nids; | 4346 | if (err < 0) |
4347 | return err; | ||
3818 | err = cx_auto_parse_auto_config(codec); | 4348 | err = cx_auto_parse_auto_config(codec); |
3819 | if (err < 0) { | 4349 | if (err < 0) { |
3820 | kfree(codec->spec); | 4350 | kfree(codec->spec); |
3821 | codec->spec = NULL; | 4351 | codec->spec = NULL; |
3822 | return err; | 4352 | return err; |
3823 | } | 4353 | } |
4354 | spec->capture_stream = &cx_auto_pcm_analog_capture; | ||
3824 | codec->patch_ops = cx_auto_patch_ops; | 4355 | codec->patch_ops = cx_auto_patch_ops; |
3825 | if (spec->beep_amp) | 4356 | if (spec->beep_amp) |
3826 | snd_hda_attach_beep_device(codec, spec->beep_amp); | 4357 | snd_hda_attach_beep_device(codec, spec->beep_amp); |
@@ -3830,7 +4361,7 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3830 | /* | 4361 | /* |
3831 | */ | 4362 | */ |
3832 | 4363 | ||
3833 | static struct hda_codec_preset snd_hda_preset_conexant[] = { | 4364 | static const struct hda_codec_preset snd_hda_preset_conexant[] = { |
3834 | { .id = 0x14f15045, .name = "CX20549 (Venice)", | 4365 | { .id = 0x14f15045, .name = "CX20549 (Venice)", |
3835 | .patch = patch_cxt5045 }, | 4366 | .patch = patch_cxt5045 }, |
3836 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", | 4367 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", |