diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 1835 |
1 files changed, 1492 insertions, 343 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 972e7c453b3d..7bbc5f237a5e 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 | ||
@@ -49,17 +50,22 @@ | |||
49 | #define AUTO_MIC_PORTB (1 << 1) | 50 | #define AUTO_MIC_PORTB (1 << 1) |
50 | #define AUTO_MIC_PORTC (1 << 2) | 51 | #define AUTO_MIC_PORTC (1 << 2) |
51 | 52 | ||
52 | struct conexant_jack { | 53 | struct pin_dac_pair { |
53 | 54 | hda_nid_t pin; | |
54 | hda_nid_t nid; | 55 | hda_nid_t dac; |
55 | int type; | 56 | int type; |
56 | struct snd_jack *jack; | 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 */ | ||
58 | }; | 64 | }; |
59 | 65 | ||
60 | struct conexant_spec { | 66 | struct conexant_spec { |
61 | 67 | ||
62 | struct snd_kcontrol_new *mixers[5]; | 68 | const struct snd_kcontrol_new *mixers[5]; |
63 | int num_mixers; | 69 | int num_mixers; |
64 | hda_nid_t vmaster_nid; | 70 | hda_nid_t vmaster_nid; |
65 | 71 | ||
@@ -76,12 +82,17 @@ struct conexant_spec { | |||
76 | */ | 82 | */ |
77 | unsigned int cur_eapd; | 83 | unsigned int cur_eapd; |
78 | unsigned int hp_present; | 84 | unsigned int hp_present; |
85 | unsigned int line_present; | ||
79 | unsigned int auto_mic; | 86 | unsigned int auto_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 */ | ||
80 | unsigned int need_dac_fix; | 90 | unsigned int need_dac_fix; |
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 */ |
@@ -103,20 +116,28 @@ struct conexant_spec { | |||
103 | 116 | ||
104 | unsigned int spdif_route; | 117 | unsigned int spdif_route; |
105 | 118 | ||
106 | /* jack detection */ | ||
107 | struct snd_array jacks; | ||
108 | |||
109 | /* dynamic controls, init_verbs and input_mux */ | 119 | /* dynamic controls, init_verbs and input_mux */ |
110 | struct auto_pin_cfg autocfg; | 120 | struct auto_pin_cfg autocfg; |
111 | 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]; | ||
112 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 124 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
125 | struct pin_dac_pair dac_info[8]; | ||
126 | int dac_info_filled; | ||
113 | 127 | ||
114 | unsigned int dell_automute; | ||
115 | unsigned int port_d_mode; | 128 | unsigned int port_d_mode; |
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 */ | ||
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; |
118 | unsigned int thinkpad:1; | 136 | unsigned int thinkpad:1; |
119 | unsigned int hp_laptop:1; | 137 | unsigned int hp_laptop:1; |
138 | unsigned int asus:1; | ||
139 | |||
140 | unsigned int adc_switching:1; | ||
120 | 141 | ||
121 | unsigned int ext_mic_present; | 142 | unsigned int ext_mic_present; |
122 | unsigned int recording; | 143 | unsigned int recording; |
@@ -226,7 +247,7 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
226 | 247 | ||
227 | 248 | ||
228 | 249 | ||
229 | static struct hda_pcm_stream conexant_pcm_analog_playback = { | 250 | static const struct hda_pcm_stream conexant_pcm_analog_playback = { |
230 | .substreams = 1, | 251 | .substreams = 1, |
231 | .channels_min = 2, | 252 | .channels_min = 2, |
232 | .channels_max = 2, | 253 | .channels_max = 2, |
@@ -238,7 +259,7 @@ static struct hda_pcm_stream conexant_pcm_analog_playback = { | |||
238 | }, | 259 | }, |
239 | }; | 260 | }; |
240 | 261 | ||
241 | static struct hda_pcm_stream conexant_pcm_analog_capture = { | 262 | static const struct hda_pcm_stream conexant_pcm_analog_capture = { |
242 | .substreams = 1, | 263 | .substreams = 1, |
243 | .channels_min = 2, | 264 | .channels_min = 2, |
244 | .channels_max = 2, | 265 | .channels_max = 2, |
@@ -250,7 +271,7 @@ static struct hda_pcm_stream conexant_pcm_analog_capture = { | |||
250 | }; | 271 | }; |
251 | 272 | ||
252 | 273 | ||
253 | static struct hda_pcm_stream conexant_pcm_digital_playback = { | 274 | static const struct hda_pcm_stream conexant_pcm_digital_playback = { |
254 | .substreams = 1, | 275 | .substreams = 1, |
255 | .channels_min = 2, | 276 | .channels_min = 2, |
256 | .channels_max = 2, | 277 | .channels_max = 2, |
@@ -262,7 +283,7 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = { | |||
262 | }, | 283 | }, |
263 | }; | 284 | }; |
264 | 285 | ||
265 | static struct hda_pcm_stream conexant_pcm_digital_capture = { | 286 | static const struct hda_pcm_stream conexant_pcm_digital_capture = { |
266 | .substreams = 1, | 287 | .substreams = 1, |
267 | .channels_min = 2, | 288 | .channels_min = 2, |
268 | .channels_max = 2, | 289 | .channels_max = 2, |
@@ -293,7 +314,7 @@ static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
293 | return 0; | 314 | return 0; |
294 | } | 315 | } |
295 | 316 | ||
296 | static struct hda_pcm_stream cx5051_pcm_analog_capture = { | 317 | static const struct hda_pcm_stream cx5051_pcm_analog_capture = { |
297 | .substreams = 1, | 318 | .substreams = 1, |
298 | .channels_min = 2, | 319 | .channels_min = 2, |
299 | .channels_max = 2, | 320 | .channels_max = 2, |
@@ -318,13 +339,19 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
318 | spec->multiout.max_channels; | 339 | spec->multiout.max_channels; |
319 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 340 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
320 | spec->multiout.dac_nids[0]; | 341 | spec->multiout.dac_nids[0]; |
321 | if (codec->vendor_id == 0x14f15051) | 342 | if (spec->capture_stream) |
322 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | 343 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; |
323 | cx5051_pcm_analog_capture; | 344 | else { |
324 | else | 345 | if (codec->vendor_id == 0x14f15051) |
325 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | 346 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = |
326 | conexant_pcm_analog_capture; | 347 | cx5051_pcm_analog_capture; |
327 | 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 | } | ||
328 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 355 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
329 | 356 | ||
330 | if (spec->multiout.dig_out_nid) { | 357 | if (spec->multiout.dig_out_nid) { |
@@ -342,6 +369,8 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
342 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | 369 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = |
343 | spec->dig_in_nid; | 370 | spec->dig_in_nid; |
344 | } | 371 | } |
372 | if (spec->slave_dig_outs[0]) | ||
373 | codec->slave_dig_outs = spec->slave_dig_outs; | ||
345 | } | 374 | } |
346 | 375 | ||
347 | return 0; | 376 | return 0; |
@@ -379,65 +408,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
379 | &spec->cur_mux[adc_idx]); | 408 | &spec->cur_mux[adc_idx]); |
380 | } | 409 | } |
381 | 410 | ||
382 | #ifdef CONFIG_SND_HDA_INPUT_JACK | ||
383 | static void conexant_free_jack_priv(struct snd_jack *jack) | ||
384 | { | ||
385 | struct conexant_jack *jacks = jack->private_data; | ||
386 | jacks->nid = 0; | ||
387 | jacks->jack = NULL; | ||
388 | } | ||
389 | |||
390 | static int conexant_add_jack(struct hda_codec *codec, | ||
391 | hda_nid_t nid, int type) | ||
392 | { | ||
393 | struct conexant_spec *spec; | ||
394 | struct conexant_jack *jack; | ||
395 | const char *name; | ||
396 | int err; | ||
397 | |||
398 | spec = codec->spec; | ||
399 | snd_array_init(&spec->jacks, sizeof(*jack), 32); | ||
400 | jack = snd_array_new(&spec->jacks); | ||
401 | name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; | ||
402 | |||
403 | if (!jack) | ||
404 | return -ENOMEM; | ||
405 | |||
406 | jack->nid = nid; | ||
407 | jack->type = type; | ||
408 | |||
409 | err = snd_jack_new(codec->bus->card, name, type, &jack->jack); | ||
410 | if (err < 0) | ||
411 | return err; | ||
412 | jack->jack->private_data = jack; | ||
413 | jack->jack->private_free = conexant_free_jack_priv; | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) | ||
418 | { | ||
419 | struct conexant_spec *spec = codec->spec; | ||
420 | struct conexant_jack *jacks = spec->jacks.list; | ||
421 | |||
422 | if (jacks) { | ||
423 | int i; | ||
424 | for (i = 0; i < spec->jacks.used; i++) { | ||
425 | if (jacks->nid == nid) { | ||
426 | unsigned int present; | ||
427 | present = snd_hda_jack_detect(codec, nid); | ||
428 | |||
429 | present = (present) ? jacks->type : 0 ; | ||
430 | |||
431 | snd_jack_report(jacks->jack, | ||
432 | present); | ||
433 | } | ||
434 | jacks++; | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | static int conexant_init_jacks(struct hda_codec *codec) | 411 | static int conexant_init_jacks(struct hda_codec *codec) |
440 | { | 412 | { |
413 | #ifdef CONFIG_SND_HDA_INPUT_JACK | ||
441 | struct conexant_spec *spec = codec->spec; | 414 | struct conexant_spec *spec = codec->spec; |
442 | int i; | 415 | int i; |
443 | 416 | ||
@@ -449,15 +422,15 @@ static int conexant_init_jacks(struct hda_codec *codec) | |||
449 | int err = 0; | 422 | int err = 0; |
450 | switch (hv->param ^ AC_USRSP_EN) { | 423 | switch (hv->param ^ AC_USRSP_EN) { |
451 | case CONEXANT_HP_EVENT: | 424 | case CONEXANT_HP_EVENT: |
452 | err = conexant_add_jack(codec, hv->nid, | 425 | err = snd_hda_input_jack_add(codec, hv->nid, |
453 | SND_JACK_HEADPHONE); | 426 | SND_JACK_HEADPHONE, NULL); |
454 | conexant_report_jack(codec, hv->nid); | 427 | snd_hda_input_jack_report(codec, hv->nid); |
455 | break; | 428 | break; |
456 | case CXT5051_PORTC_EVENT: | 429 | case CXT5051_PORTC_EVENT: |
457 | case CONEXANT_MIC_EVENT: | 430 | case CONEXANT_MIC_EVENT: |
458 | err = conexant_add_jack(codec, hv->nid, | 431 | err = snd_hda_input_jack_add(codec, hv->nid, |
459 | SND_JACK_MICROPHONE); | 432 | SND_JACK_MICROPHONE, NULL); |
460 | conexant_report_jack(codec, hv->nid); | 433 | snd_hda_input_jack_report(codec, hv->nid); |
461 | break; | 434 | break; |
462 | } | 435 | } |
463 | if (err < 0) | 436 | if (err < 0) |
@@ -465,19 +438,9 @@ static int conexant_init_jacks(struct hda_codec *codec) | |||
465 | ++hv; | 438 | ++hv; |
466 | } | 439 | } |
467 | } | 440 | } |
468 | return 0; | 441 | #endif /* CONFIG_SND_HDA_INPUT_JACK */ |
469 | |||
470 | } | ||
471 | #else | ||
472 | static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) | ||
473 | { | ||
474 | } | ||
475 | |||
476 | static inline int conexant_init_jacks(struct hda_codec *codec) | ||
477 | { | ||
478 | return 0; | 442 | return 0; |
479 | } | 443 | } |
480 | #endif | ||
481 | 444 | ||
482 | static int conexant_init(struct hda_codec *codec) | 445 | static int conexant_init(struct hda_codec *codec) |
483 | { | 446 | { |
@@ -491,23 +454,12 @@ static int conexant_init(struct hda_codec *codec) | |||
491 | 454 | ||
492 | static void conexant_free(struct hda_codec *codec) | 455 | static void conexant_free(struct hda_codec *codec) |
493 | { | 456 | { |
494 | #ifdef CONFIG_SND_HDA_INPUT_JACK | 457 | snd_hda_input_jack_free(codec); |
495 | struct conexant_spec *spec = codec->spec; | ||
496 | if (spec->jacks.list) { | ||
497 | struct conexant_jack *jacks = spec->jacks.list; | ||
498 | int i; | ||
499 | for (i = 0; i < spec->jacks.used; i++, jacks++) { | ||
500 | if (jacks->jack) | ||
501 | snd_device_free(codec->bus->card, jacks->jack); | ||
502 | } | ||
503 | snd_array_free(&spec->jacks); | ||
504 | } | ||
505 | #endif | ||
506 | snd_hda_detach_beep_device(codec); | 458 | snd_hda_detach_beep_device(codec); |
507 | kfree(codec->spec); | 459 | kfree(codec->spec); |
508 | } | 460 | } |
509 | 461 | ||
510 | static struct snd_kcontrol_new cxt_capture_mixers[] = { | 462 | static const struct snd_kcontrol_new cxt_capture_mixers[] = { |
511 | { | 463 | { |
512 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 464 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
513 | .name = "Capture Source", | 465 | .name = "Capture Source", |
@@ -520,22 +472,28 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { | |||
520 | 472 | ||
521 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 473 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
522 | /* additional beep mixers; the actual parameters are overwritten at build */ | 474 | /* additional beep mixers; the actual parameters are overwritten at build */ |
523 | static struct snd_kcontrol_new cxt_beep_mixer[] = { | 475 | static const struct snd_kcontrol_new cxt_beep_mixer[] = { |
524 | 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), |
525 | 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), |
526 | { } /* end */ | 478 | { } /* end */ |
527 | }; | 479 | }; |
528 | #endif | 480 | #endif |
529 | 481 | ||
530 | static const char *slave_vols[] = { | 482 | static const char * const slave_vols[] = { |
531 | "Headphone Playback Volume", | 483 | "Headphone Playback Volume", |
532 | "Speaker Playback Volume", | 484 | "Speaker Playback Volume", |
485 | "Front Playback Volume", | ||
486 | "Surround Playback Volume", | ||
487 | "CLFE Playback Volume", | ||
533 | NULL | 488 | NULL |
534 | }; | 489 | }; |
535 | 490 | ||
536 | static const char *slave_sws[] = { | 491 | static const char * const slave_sws[] = { |
537 | "Headphone Playback Switch", | 492 | "Headphone Playback Switch", |
538 | "Speaker Playback Switch", | 493 | "Speaker Playback Switch", |
494 | "Front Playback Switch", | ||
495 | "Surround Playback Switch", | ||
496 | "CLFE Playback Switch", | ||
539 | NULL | 497 | NULL |
540 | }; | 498 | }; |
541 | 499 | ||
@@ -595,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec) | |||
595 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 553 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
596 | /* create beep controls if needed */ | 554 | /* create beep controls if needed */ |
597 | if (spec->beep_amp) { | 555 | if (spec->beep_amp) { |
598 | struct snd_kcontrol_new *knew; | 556 | const struct snd_kcontrol_new *knew; |
599 | for (knew = cxt_beep_mixer; knew->name; knew++) { | 557 | for (knew = cxt_beep_mixer; knew->name; knew++) { |
600 | struct snd_kcontrol *kctl; | 558 | struct snd_kcontrol *kctl; |
601 | kctl = snd_ctl_new1(knew, codec); | 559 | kctl = snd_ctl_new1(knew, codec); |
@@ -620,7 +578,7 @@ static int conexant_suspend(struct hda_codec *codec, pm_message_t state) | |||
620 | } | 578 | } |
621 | #endif | 579 | #endif |
622 | 580 | ||
623 | static struct hda_codec_ops conexant_patch_ops = { | 581 | static const struct hda_codec_ops conexant_patch_ops = { |
624 | .build_controls = conexant_build_controls, | 582 | .build_controls = conexant_build_controls, |
625 | .build_pcms = conexant_build_pcms, | 583 | .build_pcms = conexant_build_pcms, |
626 | .init = conexant_init, | 584 | .init = conexant_init, |
@@ -638,6 +596,7 @@ static struct hda_codec_ops conexant_patch_ops = { | |||
638 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ | 596 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ |
639 | #endif | 597 | #endif |
640 | 598 | ||
599 | static int patch_conexant_auto(struct hda_codec *codec); | ||
641 | /* | 600 | /* |
642 | * EAPD control | 601 | * EAPD control |
643 | * the private value = nid | (invert << 8) | 602 | * the private value = nid | (invert << 8) |
@@ -736,16 +695,16 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
736 | 695 | ||
737 | /* Conexant 5045 specific */ | 696 | /* Conexant 5045 specific */ |
738 | 697 | ||
739 | static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; | 698 | static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; |
740 | static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; | 699 | static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; |
741 | static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; | 700 | static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; |
742 | #define CXT5045_SPDIF_OUT 0x18 | 701 | #define CXT5045_SPDIF_OUT 0x18 |
743 | 702 | ||
744 | static struct hda_channel_mode cxt5045_modes[1] = { | 703 | static const struct hda_channel_mode cxt5045_modes[1] = { |
745 | { 2, NULL }, | 704 | { 2, NULL }, |
746 | }; | 705 | }; |
747 | 706 | ||
748 | static struct hda_input_mux cxt5045_capture_source = { | 707 | static const struct hda_input_mux cxt5045_capture_source = { |
749 | .num_items = 2, | 708 | .num_items = 2, |
750 | .items = { | 709 | .items = { |
751 | { "IntMic", 0x1 }, | 710 | { "IntMic", 0x1 }, |
@@ -753,7 +712,7 @@ static struct hda_input_mux cxt5045_capture_source = { | |||
753 | } | 712 | } |
754 | }; | 713 | }; |
755 | 714 | ||
756 | static struct hda_input_mux cxt5045_capture_source_benq = { | 715 | static const struct hda_input_mux cxt5045_capture_source_benq = { |
757 | .num_items = 5, | 716 | .num_items = 5, |
758 | .items = { | 717 | .items = { |
759 | { "IntMic", 0x1 }, | 718 | { "IntMic", 0x1 }, |
@@ -764,7 +723,7 @@ static struct hda_input_mux cxt5045_capture_source_benq = { | |||
764 | } | 723 | } |
765 | }; | 724 | }; |
766 | 725 | ||
767 | static struct hda_input_mux cxt5045_capture_source_hp530 = { | 726 | static const struct hda_input_mux cxt5045_capture_source_hp530 = { |
768 | .num_items = 2, | 727 | .num_items = 2, |
769 | .items = { | 728 | .items = { |
770 | { "ExtMic", 0x1 }, | 729 | { "ExtMic", 0x1 }, |
@@ -797,7 +756,7 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
797 | } | 756 | } |
798 | 757 | ||
799 | /* bind volumes of both NID 0x10 and 0x11 */ | 758 | /* bind volumes of both NID 0x10 and 0x11 */ |
800 | static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { | 759 | static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = { |
801 | .ops = &snd_hda_bind_vol, | 760 | .ops = &snd_hda_bind_vol, |
802 | .values = { | 761 | .values = { |
803 | HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), | 762 | HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), |
@@ -809,12 +768,12 @@ static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { | |||
809 | /* toggle input of built-in and mic jack appropriately */ | 768 | /* toggle input of built-in and mic jack appropriately */ |
810 | static void cxt5045_hp_automic(struct hda_codec *codec) | 769 | static void cxt5045_hp_automic(struct hda_codec *codec) |
811 | { | 770 | { |
812 | static struct hda_verb mic_jack_on[] = { | 771 | static const struct hda_verb mic_jack_on[] = { |
813 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 772 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
814 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 773 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, |
815 | {} | 774 | {} |
816 | }; | 775 | }; |
817 | static struct hda_verb mic_jack_off[] = { | 776 | static const struct hda_verb mic_jack_off[] = { |
818 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 777 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, |
819 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 778 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, |
820 | {} | 779 | {} |
@@ -858,17 +817,17 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, | |||
858 | } | 817 | } |
859 | } | 818 | } |
860 | 819 | ||
861 | static struct snd_kcontrol_new cxt5045_mixers[] = { | 820 | static const struct snd_kcontrol_new cxt5045_mixers[] = { |
862 | HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), | 821 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), |
863 | HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), | 822 | HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), |
864 | HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), | 823 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), |
865 | HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), | 824 | HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), |
866 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), | 825 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), |
867 | HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), | 826 | HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), |
868 | HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT), | 827 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), |
869 | HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT), | 828 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT), |
870 | HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT), | 829 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT), |
871 | HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT), | 830 | HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT), |
872 | HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), | 831 | HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), |
873 | { | 832 | { |
874 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 833 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -882,7 +841,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
882 | {} | 841 | {} |
883 | }; | 842 | }; |
884 | 843 | ||
885 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | 844 | static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { |
886 | HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), | 845 | HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), |
887 | HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), | 846 | HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), |
888 | HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), | 847 | HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), |
@@ -899,17 +858,17 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | |||
899 | {} | 858 | {} |
900 | }; | 859 | }; |
901 | 860 | ||
902 | static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | 861 | static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { |
903 | HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), | 862 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), |
904 | HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), | 863 | HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), |
905 | HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), | 864 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), |
906 | HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), | 865 | HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), |
907 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), | 866 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), |
908 | HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), | 867 | HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), |
909 | HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT), | 868 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT), |
910 | HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT), | 869 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT), |
911 | HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT), | 870 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT), |
912 | HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT), | 871 | HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT), |
913 | HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), | 872 | HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), |
914 | { | 873 | { |
915 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 874 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -923,7 +882,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | |||
923 | {} | 882 | {} |
924 | }; | 883 | }; |
925 | 884 | ||
926 | static struct hda_verb cxt5045_init_verbs[] = { | 885 | static const struct hda_verb cxt5045_init_verbs[] = { |
927 | /* Line in, Mic */ | 886 | /* Line in, Mic */ |
928 | {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 }, |
929 | {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 }, |
@@ -937,7 +896,7 @@ static struct hda_verb cxt5045_init_verbs[] = { | |||
937 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | 896 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
938 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | 897 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
939 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 898 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
940 | /* Record selector: Int mic */ | 899 | /* Record selector: Internal mic */ |
941 | {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, | 900 | {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, |
942 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, | 901 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, |
943 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | 902 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, |
@@ -949,8 +908,8 @@ static struct hda_verb cxt5045_init_verbs[] = { | |||
949 | { } /* end */ | 908 | { } /* end */ |
950 | }; | 909 | }; |
951 | 910 | ||
952 | static struct hda_verb cxt5045_benq_init_verbs[] = { | 911 | static const struct hda_verb cxt5045_benq_init_verbs[] = { |
953 | /* Int Mic, Mic */ | 912 | /* Internal Mic, Mic */ |
954 | {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 }, |
955 | {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 }, |
956 | /* Line In,HP, Amp */ | 915 | /* Line In,HP, Amp */ |
@@ -963,7 +922,7 @@ static struct hda_verb cxt5045_benq_init_verbs[] = { | |||
963 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | 922 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, |
964 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | 923 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, |
965 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 924 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
966 | /* Record selector: Int mic */ | 925 | /* Record selector: Internal mic */ |
967 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, | 926 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, |
968 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, | 927 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, |
969 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | 928 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, |
@@ -975,13 +934,13 @@ static struct hda_verb cxt5045_benq_init_verbs[] = { | |||
975 | { } /* end */ | 934 | { } /* end */ |
976 | }; | 935 | }; |
977 | 936 | ||
978 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { | 937 | static const struct hda_verb cxt5045_hp_sense_init_verbs[] = { |
979 | /* pin sensing on HP jack */ | 938 | /* pin sensing on HP jack */ |
980 | {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}, |
981 | { } /* end */ | 940 | { } /* end */ |
982 | }; | 941 | }; |
983 | 942 | ||
984 | static struct hda_verb cxt5045_mic_sense_init_verbs[] = { | 943 | static const struct hda_verb cxt5045_mic_sense_init_verbs[] = { |
985 | /* pin sensing on HP jack */ | 944 | /* pin sensing on HP jack */ |
986 | {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}, |
987 | { } /* end */ | 946 | { } /* end */ |
@@ -991,7 +950,7 @@ static struct hda_verb cxt5045_mic_sense_init_verbs[] = { | |||
991 | /* Test configuration for debugging, modelled after the ALC260 test | 950 | /* Test configuration for debugging, modelled after the ALC260 test |
992 | * configuration. | 951 | * configuration. |
993 | */ | 952 | */ |
994 | static struct hda_input_mux cxt5045_test_capture_source = { | 953 | static const struct hda_input_mux cxt5045_test_capture_source = { |
995 | .num_items = 5, | 954 | .num_items = 5, |
996 | .items = { | 955 | .items = { |
997 | { "MIXER", 0x0 }, | 956 | { "MIXER", 0x0 }, |
@@ -1002,7 +961,7 @@ static struct hda_input_mux cxt5045_test_capture_source = { | |||
1002 | }, | 961 | }, |
1003 | }; | 962 | }; |
1004 | 963 | ||
1005 | static struct snd_kcontrol_new cxt5045_test_mixer[] = { | 964 | static const struct snd_kcontrol_new cxt5045_test_mixer[] = { |
1006 | 965 | ||
1007 | /* Output controls */ | 966 | /* Output controls */ |
1008 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), | 967 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), |
@@ -1052,7 +1011,7 @@ static struct snd_kcontrol_new cxt5045_test_mixer[] = { | |||
1052 | { } /* end */ | 1011 | { } /* end */ |
1053 | }; | 1012 | }; |
1054 | 1013 | ||
1055 | static struct hda_verb cxt5045_test_init_verbs[] = { | 1014 | static const struct hda_verb cxt5045_test_init_verbs[] = { |
1056 | /* Set connections */ | 1015 | /* Set connections */ |
1057 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, | 1016 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, |
1058 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, | 1017 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, |
@@ -1121,10 +1080,11 @@ enum { | |||
1121 | #ifdef CONFIG_SND_DEBUG | 1080 | #ifdef CONFIG_SND_DEBUG |
1122 | CXT5045_TEST, | 1081 | CXT5045_TEST, |
1123 | #endif | 1082 | #endif |
1083 | CXT5045_AUTO, | ||
1124 | CXT5045_MODELS | 1084 | CXT5045_MODELS |
1125 | }; | 1085 | }; |
1126 | 1086 | ||
1127 | static const char *cxt5045_models[CXT5045_MODELS] = { | 1087 | static const char * const cxt5045_models[CXT5045_MODELS] = { |
1128 | [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", | 1088 | [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", |
1129 | [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", | 1089 | [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", |
1130 | [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", | 1090 | [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", |
@@ -1133,9 +1093,10 @@ static const char *cxt5045_models[CXT5045_MODELS] = { | |||
1133 | #ifdef CONFIG_SND_DEBUG | 1093 | #ifdef CONFIG_SND_DEBUG |
1134 | [CXT5045_TEST] = "test", | 1094 | [CXT5045_TEST] = "test", |
1135 | #endif | 1095 | #endif |
1096 | [CXT5045_AUTO] = "auto", | ||
1136 | }; | 1097 | }; |
1137 | 1098 | ||
1138 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | 1099 | static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { |
1139 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), | 1100 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), |
1140 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", | 1101 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", |
1141 | CXT5045_LAPTOP_HPSENSE), | 1102 | CXT5045_LAPTOP_HPSENSE), |
@@ -1159,6 +1120,16 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1159 | struct conexant_spec *spec; | 1120 | struct conexant_spec *spec; |
1160 | int board_config; | 1121 | int board_config; |
1161 | 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 | |||
1162 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1133 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1163 | if (!spec) | 1134 | if (!spec) |
1164 | return -ENOMEM; | 1135 | return -ENOMEM; |
@@ -1185,9 +1156,6 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1185 | 1156 | ||
1186 | codec->patch_ops = conexant_patch_ops; | 1157 | codec->patch_ops = conexant_patch_ops; |
1187 | 1158 | ||
1188 | board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, | ||
1189 | cxt5045_models, | ||
1190 | cxt5045_cfg_tbl); | ||
1191 | switch (board_config) { | 1159 | switch (board_config) { |
1192 | case CXT5045_LAPTOP_HPSENSE: | 1160 | case CXT5045_LAPTOP_HPSENSE: |
1193 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | 1161 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; |
@@ -1270,15 +1238,15 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1270 | /* Conexant 5047 specific */ | 1238 | /* Conexant 5047 specific */ |
1271 | #define CXT5047_SPDIF_OUT 0x11 | 1239 | #define CXT5047_SPDIF_OUT 0x11 |
1272 | 1240 | ||
1273 | static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ | 1241 | static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ |
1274 | static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; | 1242 | static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; |
1275 | static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; | 1243 | static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; |
1276 | 1244 | ||
1277 | static struct hda_channel_mode cxt5047_modes[1] = { | 1245 | static const struct hda_channel_mode cxt5047_modes[1] = { |
1278 | { 2, NULL }, | 1246 | { 2, NULL }, |
1279 | }; | 1247 | }; |
1280 | 1248 | ||
1281 | static struct hda_input_mux cxt5047_toshiba_capture_source = { | 1249 | static const struct hda_input_mux cxt5047_toshiba_capture_source = { |
1282 | .num_items = 2, | 1250 | .num_items = 2, |
1283 | .items = { | 1251 | .items = { |
1284 | { "ExtMic", 0x2 }, | 1252 | { "ExtMic", 0x2 }, |
@@ -1330,12 +1298,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) | |||
1330 | /* toggle input of built-in and mic jack appropriately */ | 1298 | /* toggle input of built-in and mic jack appropriately */ |
1331 | static void cxt5047_hp_automic(struct hda_codec *codec) | 1299 | static void cxt5047_hp_automic(struct hda_codec *codec) |
1332 | { | 1300 | { |
1333 | static struct hda_verb mic_jack_on[] = { | 1301 | static const struct hda_verb mic_jack_on[] = { |
1334 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1302 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
1335 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1303 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1336 | {} | 1304 | {} |
1337 | }; | 1305 | }; |
1338 | static struct hda_verb mic_jack_off[] = { | 1306 | static const struct hda_verb mic_jack_off[] = { |
1339 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 1307 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
1340 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1308 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1341 | {} | 1309 | {} |
@@ -1363,10 +1331,10 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec, | |||
1363 | } | 1331 | } |
1364 | } | 1332 | } |
1365 | 1333 | ||
1366 | static struct snd_kcontrol_new cxt5047_base_mixers[] = { | 1334 | static const struct snd_kcontrol_new cxt5047_base_mixers[] = { |
1367 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), | 1335 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), |
1368 | HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), | 1336 | HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), |
1369 | HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT), | 1337 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), |
1370 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), | 1338 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), |
1371 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | 1339 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), |
1372 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | 1340 | HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), |
@@ -1383,19 +1351,19 @@ static struct snd_kcontrol_new cxt5047_base_mixers[] = { | |||
1383 | {} | 1351 | {} |
1384 | }; | 1352 | }; |
1385 | 1353 | ||
1386 | static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { | 1354 | static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { |
1387 | /* See the note in cxt5047_hp_master_sw_put */ | 1355 | /* See the note in cxt5047_hp_master_sw_put */ |
1388 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), | 1356 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), |
1389 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), | 1357 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), |
1390 | {} | 1358 | {} |
1391 | }; | 1359 | }; |
1392 | 1360 | ||
1393 | static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { | 1361 | static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { |
1394 | HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), | 1362 | HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), |
1395 | { } /* end */ | 1363 | { } /* end */ |
1396 | }; | 1364 | }; |
1397 | 1365 | ||
1398 | static struct hda_verb cxt5047_init_verbs[] = { | 1366 | static const struct hda_verb cxt5047_init_verbs[] = { |
1399 | /* Line in, Mic, Built-in Mic */ | 1367 | /* Line in, Mic, Built-in Mic */ |
1400 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 1368 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
1401 | {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 }, |
@@ -1422,7 +1390,7 @@ static struct hda_verb cxt5047_init_verbs[] = { | |||
1422 | }; | 1390 | }; |
1423 | 1391 | ||
1424 | /* configuration for Toshiba Laptops */ | 1392 | /* configuration for Toshiba Laptops */ |
1425 | static struct hda_verb cxt5047_toshiba_init_verbs[] = { | 1393 | static const struct hda_verb cxt5047_toshiba_init_verbs[] = { |
1426 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ | 1394 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ |
1427 | {} | 1395 | {} |
1428 | }; | 1396 | }; |
@@ -1431,7 +1399,7 @@ static struct hda_verb cxt5047_toshiba_init_verbs[] = { | |||
1431 | * configuration. | 1399 | * configuration. |
1432 | */ | 1400 | */ |
1433 | #ifdef CONFIG_SND_DEBUG | 1401 | #ifdef CONFIG_SND_DEBUG |
1434 | static struct hda_input_mux cxt5047_test_capture_source = { | 1402 | static const struct hda_input_mux cxt5047_test_capture_source = { |
1435 | .num_items = 4, | 1403 | .num_items = 4, |
1436 | .items = { | 1404 | .items = { |
1437 | { "LINE1 pin", 0x0 }, | 1405 | { "LINE1 pin", 0x0 }, |
@@ -1441,7 +1409,7 @@ static struct hda_input_mux cxt5047_test_capture_source = { | |||
1441 | }, | 1409 | }, |
1442 | }; | 1410 | }; |
1443 | 1411 | ||
1444 | static struct snd_kcontrol_new cxt5047_test_mixer[] = { | 1412 | static const struct snd_kcontrol_new cxt5047_test_mixer[] = { |
1445 | 1413 | ||
1446 | /* Output only controls */ | 1414 | /* Output only controls */ |
1447 | HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), | 1415 | HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), |
@@ -1494,7 +1462,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { | |||
1494 | { } /* end */ | 1462 | { } /* end */ |
1495 | }; | 1463 | }; |
1496 | 1464 | ||
1497 | static struct hda_verb cxt5047_test_init_verbs[] = { | 1465 | static const struct hda_verb cxt5047_test_init_verbs[] = { |
1498 | /* Enable retasking pins as output, initially without power amp */ | 1466 | /* Enable retasking pins as output, initially without power amp */ |
1499 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 1467 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1500 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 1468 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
@@ -1566,19 +1534,21 @@ enum { | |||
1566 | #ifdef CONFIG_SND_DEBUG | 1534 | #ifdef CONFIG_SND_DEBUG |
1567 | CXT5047_TEST, | 1535 | CXT5047_TEST, |
1568 | #endif | 1536 | #endif |
1537 | CXT5047_AUTO, | ||
1569 | CXT5047_MODELS | 1538 | CXT5047_MODELS |
1570 | }; | 1539 | }; |
1571 | 1540 | ||
1572 | static const char *cxt5047_models[CXT5047_MODELS] = { | 1541 | static const char * const cxt5047_models[CXT5047_MODELS] = { |
1573 | [CXT5047_LAPTOP] = "laptop", | 1542 | [CXT5047_LAPTOP] = "laptop", |
1574 | [CXT5047_LAPTOP_HP] = "laptop-hp", | 1543 | [CXT5047_LAPTOP_HP] = "laptop-hp", |
1575 | [CXT5047_LAPTOP_EAPD] = "laptop-eapd", | 1544 | [CXT5047_LAPTOP_EAPD] = "laptop-eapd", |
1576 | #ifdef CONFIG_SND_DEBUG | 1545 | #ifdef CONFIG_SND_DEBUG |
1577 | [CXT5047_TEST] = "test", | 1546 | [CXT5047_TEST] = "test", |
1578 | #endif | 1547 | #endif |
1548 | [CXT5047_AUTO] = "auto", | ||
1579 | }; | 1549 | }; |
1580 | 1550 | ||
1581 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | 1551 | static const struct snd_pci_quirk cxt5047_cfg_tbl[] = { |
1582 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | 1552 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), |
1583 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", | 1553 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", |
1584 | CXT5047_LAPTOP), | 1554 | CXT5047_LAPTOP), |
@@ -1591,6 +1561,16 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1591 | struct conexant_spec *spec; | 1561 | struct conexant_spec *spec; |
1592 | int board_config; | 1562 | int board_config; |
1593 | 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 | |||
1594 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1574 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1595 | if (!spec) | 1575 | if (!spec) |
1596 | return -ENOMEM; | 1576 | return -ENOMEM; |
@@ -1614,9 +1594,6 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1614 | 1594 | ||
1615 | codec->patch_ops = conexant_patch_ops; | 1595 | codec->patch_ops = conexant_patch_ops; |
1616 | 1596 | ||
1617 | board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, | ||
1618 | cxt5047_models, | ||
1619 | cxt5047_cfg_tbl); | ||
1620 | switch (board_config) { | 1597 | switch (board_config) { |
1621 | case CXT5047_LAPTOP: | 1598 | case CXT5047_LAPTOP: |
1622 | spec->num_mixers = 2; | 1599 | spec->num_mixers = 2; |
@@ -1665,10 +1642,10 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1665 | } | 1642 | } |
1666 | 1643 | ||
1667 | /* Conexant 5051 specific */ | 1644 | /* Conexant 5051 specific */ |
1668 | static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; | 1645 | static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; |
1669 | static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; | 1646 | static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; |
1670 | 1647 | ||
1671 | static struct hda_channel_mode cxt5051_modes[1] = { | 1648 | static const struct hda_channel_mode cxt5051_modes[1] = { |
1672 | { 2, NULL }, | 1649 | { 2, NULL }, |
1673 | }; | 1650 | }; |
1674 | 1651 | ||
@@ -1767,10 +1744,10 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, | |||
1767 | cxt5051_portc_automic(codec); | 1744 | cxt5051_portc_automic(codec); |
1768 | break; | 1745 | break; |
1769 | } | 1746 | } |
1770 | conexant_report_jack(codec, nid); | 1747 | snd_hda_input_jack_report(codec, nid); |
1771 | } | 1748 | } |
1772 | 1749 | ||
1773 | static struct snd_kcontrol_new cxt5051_playback_mixers[] = { | 1750 | static const struct snd_kcontrol_new cxt5051_playback_mixers[] = { |
1774 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 1751 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), |
1775 | { | 1752 | { |
1776 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1753 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1783,45 +1760,45 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = { | |||
1783 | {} | 1760 | {} |
1784 | }; | 1761 | }; |
1785 | 1762 | ||
1786 | static struct snd_kcontrol_new cxt5051_capture_mixers[] = { | 1763 | static const struct snd_kcontrol_new cxt5051_capture_mixers[] = { |
1787 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | 1764 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), |
1788 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1765 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1789 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | 1766 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), |
1790 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | 1767 | HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), |
1791 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | 1768 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), |
1792 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | 1769 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), |
1793 | {} | 1770 | {} |
1794 | }; | 1771 | }; |
1795 | 1772 | ||
1796 | static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | 1773 | static const struct snd_kcontrol_new cxt5051_hp_mixers[] = { |
1797 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | 1774 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), |
1798 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1775 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1799 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), | 1776 | HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT), |
1800 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), | 1777 | HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT), |
1801 | {} | 1778 | {} |
1802 | }; | 1779 | }; |
1803 | 1780 | ||
1804 | static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | 1781 | static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { |
1805 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), | 1782 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), |
1806 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), | 1783 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), |
1807 | {} | 1784 | {} |
1808 | }; | 1785 | }; |
1809 | 1786 | ||
1810 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | 1787 | static const struct snd_kcontrol_new cxt5051_f700_mixers[] = { |
1811 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), | 1788 | HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), |
1812 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), | 1789 | HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), |
1813 | {} | 1790 | {} |
1814 | }; | 1791 | }; |
1815 | 1792 | ||
1816 | static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { | 1793 | static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { |
1817 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | 1794 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), |
1818 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | 1795 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), |
1819 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | 1796 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), |
1820 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | 1797 | HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), |
1821 | {} | 1798 | {} |
1822 | }; | 1799 | }; |
1823 | 1800 | ||
1824 | static struct hda_verb cxt5051_init_verbs[] = { | 1801 | static const struct hda_verb cxt5051_init_verbs[] = { |
1825 | /* Line in, Mic */ | 1802 | /* Line in, Mic */ |
1826 | {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}, |
1827 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1804 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1837,7 +1814,7 @@ static struct hda_verb cxt5051_init_verbs[] = { | |||
1837 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | 1814 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1838 | /* DAC1 */ | 1815 | /* DAC1 */ |
1839 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1816 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1840 | /* Record selector: Int mic */ | 1817 | /* Record selector: Internal mic */ |
1841 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | 1818 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, |
1842 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | 1819 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, |
1843 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | 1820 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, |
@@ -1850,7 +1827,7 @@ static struct hda_verb cxt5051_init_verbs[] = { | |||
1850 | { } /* end */ | 1827 | { } /* end */ |
1851 | }; | 1828 | }; |
1852 | 1829 | ||
1853 | static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | 1830 | static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { |
1854 | /* Line in, Mic */ | 1831 | /* Line in, Mic */ |
1855 | {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}, |
1856 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1833 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1864,7 +1841,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | |||
1864 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | 1841 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1865 | /* DAC1 */ | 1842 | /* DAC1 */ |
1866 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1843 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1867 | /* Record selector: Int mic */ | 1844 | /* Record selector: Internal mic */ |
1868 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | 1845 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, |
1869 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | 1846 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, |
1870 | /* SPDIF route: PCM */ | 1847 | /* SPDIF route: PCM */ |
@@ -1875,7 +1852,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | |||
1875 | { } /* end */ | 1852 | { } /* end */ |
1876 | }; | 1853 | }; |
1877 | 1854 | ||
1878 | static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | 1855 | static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { |
1879 | /* Line in, Mic */ | 1856 | /* Line in, Mic */ |
1880 | {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}, |
1881 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1858 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1894,7 +1871,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1894 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, | 1871 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1895 | /* DAC1 */ | 1872 | /* DAC1 */ |
1896 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1873 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1897 | /* Record selector: Int mic */ | 1874 | /* Record selector: Internal mic */ |
1898 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | 1875 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, |
1899 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | 1876 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, |
1900 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | 1877 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, |
@@ -1908,7 +1885,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
1908 | { } /* end */ | 1885 | { } /* end */ |
1909 | }; | 1886 | }; |
1910 | 1887 | ||
1911 | static struct hda_verb cxt5051_f700_init_verbs[] = { | 1888 | static const struct hda_verb cxt5051_f700_init_verbs[] = { |
1912 | /* Line in, Mic */ | 1889 | /* Line in, Mic */ |
1913 | {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}, |
1914 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1891 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -1922,7 +1899,7 @@ static struct hda_verb cxt5051_f700_init_verbs[] = { | |||
1922 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | 1899 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, |
1923 | /* DAC1 */ | 1900 | /* DAC1 */ |
1924 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 1901 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
1925 | /* Record selector: Int mic */ | 1902 | /* Record selector: Internal mic */ |
1926 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | 1903 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, |
1927 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | 1904 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, |
1928 | /* SPDIF route: PCM */ | 1905 | /* SPDIF route: PCM */ |
@@ -1939,13 +1916,11 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, | |||
1939 | snd_hda_codec_write(codec, nid, 0, | 1916 | snd_hda_codec_write(codec, nid, 0, |
1940 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1917 | AC_VERB_SET_UNSOLICITED_ENABLE, |
1941 | AC_USRSP_EN | event); | 1918 | AC_USRSP_EN | event); |
1942 | #ifdef CONFIG_SND_HDA_INPUT_JACK | 1919 | snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL); |
1943 | conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); | 1920 | snd_hda_input_jack_report(codec, nid); |
1944 | conexant_report_jack(codec, nid); | ||
1945 | #endif | ||
1946 | } | 1921 | } |
1947 | 1922 | ||
1948 | static struct hda_verb cxt5051_ideapad_init_verbs[] = { | 1923 | static const struct hda_verb cxt5051_ideapad_init_verbs[] = { |
1949 | /* Subwoofer */ | 1924 | /* Subwoofer */ |
1950 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 1925 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
1951 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | 1926 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -1982,10 +1957,11 @@ enum { | |||
1982 | CXT5051_F700, /* HP Compaq Presario F700 */ | 1957 | CXT5051_F700, /* HP Compaq Presario F700 */ |
1983 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | 1958 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ |
1984 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ | 1959 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ |
1960 | CXT5051_AUTO, /* auto-parser */ | ||
1985 | CXT5051_MODELS | 1961 | CXT5051_MODELS |
1986 | }; | 1962 | }; |
1987 | 1963 | ||
1988 | static const char *cxt5051_models[CXT5051_MODELS] = { | 1964 | static const char *const cxt5051_models[CXT5051_MODELS] = { |
1989 | [CXT5051_LAPTOP] = "laptop", | 1965 | [CXT5051_LAPTOP] = "laptop", |
1990 | [CXT5051_HP] = "hp", | 1966 | [CXT5051_HP] = "hp", |
1991 | [CXT5051_HP_DV6736] = "hp-dv6736", | 1967 | [CXT5051_HP_DV6736] = "hp-dv6736", |
@@ -1993,9 +1969,10 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1993 | [CXT5051_F700] = "hp-700", | 1969 | [CXT5051_F700] = "hp-700", |
1994 | [CXT5051_TOSHIBA] = "toshiba", | 1970 | [CXT5051_TOSHIBA] = "toshiba", |
1995 | [CXT5051_IDEAPAD] = "ideapad", | 1971 | [CXT5051_IDEAPAD] = "ideapad", |
1972 | [CXT5051_AUTO] = "auto", | ||
1996 | }; | 1973 | }; |
1997 | 1974 | ||
1998 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1975 | static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
1999 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), | 1976 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), |
2000 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), | 1977 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), |
2001 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), | 1978 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), |
@@ -2013,6 +1990,16 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
2013 | struct conexant_spec *spec; | 1990 | struct conexant_spec *spec; |
2014 | int board_config; | 1991 | int board_config; |
2015 | 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 | |||
2016 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2003 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
2017 | if (!spec) | 2004 | if (!spec) |
2018 | return -ENOMEM; | 2005 | return -ENOMEM; |
@@ -2043,9 +2030,6 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
2043 | 2030 | ||
2044 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | 2031 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; |
2045 | 2032 | ||
2046 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
2047 | cxt5051_models, | ||
2048 | cxt5051_cfg_tbl); | ||
2049 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; | 2033 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; |
2050 | switch (board_config) { | 2034 | switch (board_config) { |
2051 | case CXT5051_HP: | 2035 | case CXT5051_HP: |
@@ -2087,39 +2071,49 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
2087 | 2071 | ||
2088 | /* Conexant 5066 specific */ | 2072 | /* Conexant 5066 specific */ |
2089 | 2073 | ||
2090 | static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; | 2074 | static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; |
2091 | static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; | 2075 | static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; |
2092 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; | 2076 | static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; |
2093 | #define CXT5066_SPDIF_OUT 0x21 | 2077 | static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; |
2094 | 2078 | ||
2095 | /* 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, |
2096 | * 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 |
2097 | * the DC input range of the codec. */ | 2081 | * the DC input range of the codec. */ |
2098 | #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 | 2082 | #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 |
2099 | 2083 | ||
2100 | static struct hda_channel_mode cxt5066_modes[1] = { | 2084 | static const struct hda_channel_mode cxt5066_modes[1] = { |
2101 | { 2, NULL }, | 2085 | { 2, NULL }, |
2102 | }; | 2086 | }; |
2103 | 2087 | ||
2088 | #define HP_PRESENT_PORT_A (1 << 0) | ||
2089 | #define HP_PRESENT_PORT_D (1 << 1) | ||
2090 | #define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A) | ||
2091 | #define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D) | ||
2092 | |||
2104 | static void cxt5066_update_speaker(struct hda_codec *codec) | 2093 | static void cxt5066_update_speaker(struct hda_codec *codec) |
2105 | { | 2094 | { |
2106 | struct conexant_spec *spec = codec->spec; | 2095 | struct conexant_spec *spec = codec->spec; |
2107 | unsigned int pinctl; | 2096 | unsigned int pinctl; |
2108 | 2097 | ||
2109 | snd_printdd("CXT5066: update speaker, hp_present=%d\n", | 2098 | snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", |
2110 | spec->hp_present); | 2099 | spec->hp_present, spec->cur_eapd); |
2111 | 2100 | ||
2112 | /* Port A (HP) */ | 2101 | /* Port A (HP) */ |
2113 | pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0; | 2102 | pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; |
2114 | snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2103 | snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
2115 | pinctl); | 2104 | pinctl); |
2116 | 2105 | ||
2117 | /* Port D (HP/LO) */ | 2106 | /* Port D (HP/LO) */ |
2118 | pinctl = ((spec->hp_present & 2) && spec->cur_eapd) | 2107 | pinctl = spec->cur_eapd ? spec->port_d_mode : 0; |
2119 | ? spec->port_d_mode : 0; | 2108 | if (spec->dell_automute || spec->thinkpad) { |
2120 | /* Mute if Port A is connected on Thinkpad */ | 2109 | /* Mute if Port A is connected */ |
2121 | if (spec->thinkpad && (spec->hp_present & 1)) | 2110 | if (hp_port_a_present(spec)) |
2122 | pinctl = 0; | 2111 | pinctl = 0; |
2112 | } else { | ||
2113 | /* Thinkpad/Dell doesn't give pin-D status */ | ||
2114 | if (!hp_port_d_present(spec)) | ||
2115 | pinctl = 0; | ||
2116 | } | ||
2123 | snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2117 | snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
2124 | pinctl); | 2118 | pinctl); |
2125 | 2119 | ||
@@ -2127,14 +2121,6 @@ static void cxt5066_update_speaker(struct hda_codec *codec) | |||
2127 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 2121 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
2128 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2122 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
2129 | pinctl); | 2123 | pinctl); |
2130 | |||
2131 | if (spec->dell_automute) { | ||
2132 | /* DELL AIO Port Rule: PortA > PortD > IntSpk */ | ||
2133 | pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) | ||
2134 | ? PIN_OUT : 0; | ||
2135 | snd_hda_codec_write(codec, 0x1c, 0, | ||
2136 | AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | ||
2137 | } | ||
2138 | } | 2124 | } |
2139 | 2125 | ||
2140 | /* turn on/off EAPD (+ mute HP) as a master switch */ | 2126 | /* turn on/off EAPD (+ mute HP) as a master switch */ |
@@ -2250,7 +2236,7 @@ static void cxt5066_vostro_automic(struct hda_codec *codec) | |||
2250 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2236 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2251 | {} | 2237 | {} |
2252 | }; | 2238 | }; |
2253 | static struct hda_verb ext_mic_absent[] = { | 2239 | static const struct hda_verb ext_mic_absent[] = { |
2254 | /* enable internal mic, port C */ | 2240 | /* enable internal mic, port C */ |
2255 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2241 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
2256 | 2242 | ||
@@ -2283,7 +2269,7 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) | |||
2283 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2269 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2284 | {} | 2270 | {} |
2285 | }; | 2271 | }; |
2286 | static struct hda_verb ext_mic_absent[] = { | 2272 | static const struct hda_verb ext_mic_absent[] = { |
2287 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | 2273 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
2288 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2274 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
2289 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2275 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2300,6 +2286,19 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) | |||
2300 | } | 2286 | } |
2301 | } | 2287 | } |
2302 | 2288 | ||
2289 | |||
2290 | /* toggle input of built-in digital mic and mic jack appropriately */ | ||
2291 | static void cxt5066_asus_automic(struct hda_codec *codec) | ||
2292 | { | ||
2293 | unsigned int present; | ||
2294 | |||
2295 | present = snd_hda_jack_detect(codec, 0x1b); | ||
2296 | snd_printdd("CXT5066: external microphone present=%d\n", present); | ||
2297 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, | ||
2298 | present ? 1 : 0); | ||
2299 | } | ||
2300 | |||
2301 | |||
2303 | /* toggle input of built-in digital mic and mic jack appropriately */ | 2302 | /* toggle input of built-in digital mic and mic jack appropriately */ |
2304 | static void cxt5066_hp_laptop_automic(struct hda_codec *codec) | 2303 | static void cxt5066_hp_laptop_automic(struct hda_codec *codec) |
2305 | { | 2304 | { |
@@ -2318,7 +2317,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) | |||
2318 | { | 2317 | { |
2319 | unsigned int ext_present, dock_present; | 2318 | unsigned int ext_present, dock_present; |
2320 | 2319 | ||
2321 | static struct hda_verb ext_mic_present[] = { | 2320 | static const struct hda_verb ext_mic_present[] = { |
2322 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | 2321 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, |
2323 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | 2322 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, |
2324 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2323 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -2326,7 +2325,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) | |||
2326 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2325 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2327 | {} | 2326 | {} |
2328 | }; | 2327 | }; |
2329 | static struct hda_verb dock_mic_present[] = { | 2328 | static const struct hda_verb dock_mic_present[] = { |
2330 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | 2329 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, |
2331 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2330 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
2332 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2331 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -2334,7 +2333,7 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) | |||
2334 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2333 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2335 | {} | 2334 | {} |
2336 | }; | 2335 | }; |
2337 | static struct hda_verb ext_mic_absent[] = { | 2336 | static const struct hda_verb ext_mic_absent[] = { |
2338 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | 2337 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, |
2339 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2338 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
2340 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2339 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
@@ -2368,86 +2367,62 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
2368 | /* Port D */ | 2367 | /* Port D */ |
2369 | portD = snd_hda_jack_detect(codec, 0x1c); | 2368 | portD = snd_hda_jack_detect(codec, 0x1c); |
2370 | 2369 | ||
2371 | spec->hp_present = !!(portA); | 2370 | spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; |
2372 | spec->hp_present |= portD ? 2 : 0; | 2371 | spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; |
2373 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", | 2372 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", |
2374 | portA, portD, spec->hp_present); | 2373 | portA, portD, spec->hp_present); |
2375 | cxt5066_update_speaker(codec); | 2374 | cxt5066_update_speaker(codec); |
2376 | } | 2375 | } |
2377 | 2376 | ||
2378 | /* unsolicited event for jack sensing */ | 2377 | /* Dispatch the right mic autoswitch function */ |
2379 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) | 2378 | static void cxt5066_automic(struct hda_codec *codec) |
2380 | { | 2379 | { |
2381 | struct conexant_spec *spec = codec->spec; | 2380 | struct conexant_spec *spec = codec->spec; |
2382 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | ||
2383 | switch (res >> 26) { | ||
2384 | case CONEXANT_HP_EVENT: | ||
2385 | cxt5066_hp_automute(codec); | ||
2386 | break; | ||
2387 | case CONEXANT_MIC_EVENT: | ||
2388 | /* ignore mic events in DC mode; we're always using the jack */ | ||
2389 | if (!spec->dc_enable) | ||
2390 | cxt5066_olpc_automic(codec); | ||
2391 | break; | ||
2392 | } | ||
2393 | } | ||
2394 | 2381 | ||
2395 | /* unsolicited event for jack sensing */ | 2382 | if (spec->dell_vostro) |
2396 | static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) | ||
2397 | { | ||
2398 | snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26); | ||
2399 | switch (res >> 26) { | ||
2400 | case CONEXANT_HP_EVENT: | ||
2401 | cxt5066_hp_automute(codec); | ||
2402 | break; | ||
2403 | case CONEXANT_MIC_EVENT: | ||
2404 | cxt5066_vostro_automic(codec); | 2383 | cxt5066_vostro_automic(codec); |
2405 | break; | 2384 | else if (spec->ideapad) |
2406 | } | ||
2407 | } | ||
2408 | |||
2409 | /* unsolicited event for jack sensing */ | ||
2410 | static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) | ||
2411 | { | ||
2412 | snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); | ||
2413 | switch (res >> 26) { | ||
2414 | case CONEXANT_HP_EVENT: | ||
2415 | cxt5066_hp_automute(codec); | ||
2416 | break; | ||
2417 | case CONEXANT_MIC_EVENT: | ||
2418 | cxt5066_ideapad_automic(codec); | 2385 | cxt5066_ideapad_automic(codec); |
2419 | break; | 2386 | else if (spec->thinkpad) |
2420 | } | 2387 | cxt5066_thinkpad_automic(codec); |
2388 | else if (spec->hp_laptop) | ||
2389 | cxt5066_hp_laptop_automic(codec); | ||
2390 | else if (spec->asus) | ||
2391 | cxt5066_asus_automic(codec); | ||
2421 | } | 2392 | } |
2422 | 2393 | ||
2423 | /* unsolicited event for jack sensing */ | 2394 | /* unsolicited event for jack sensing */ |
2424 | static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) | 2395 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) |
2425 | { | 2396 | { |
2426 | snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); | 2397 | struct conexant_spec *spec = codec->spec; |
2398 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | ||
2427 | switch (res >> 26) { | 2399 | switch (res >> 26) { |
2428 | case CONEXANT_HP_EVENT: | 2400 | case CONEXANT_HP_EVENT: |
2429 | cxt5066_hp_automute(codec); | 2401 | cxt5066_hp_automute(codec); |
2430 | break; | 2402 | break; |
2431 | case CONEXANT_MIC_EVENT: | 2403 | case CONEXANT_MIC_EVENT: |
2432 | cxt5066_hp_laptop_automic(codec); | 2404 | /* ignore mic events in DC mode; we're always using the jack */ |
2405 | if (!spec->dc_enable) | ||
2406 | cxt5066_olpc_automic(codec); | ||
2433 | break; | 2407 | break; |
2434 | } | 2408 | } |
2435 | } | 2409 | } |
2436 | 2410 | ||
2437 | /* unsolicited event for jack sensing */ | 2411 | /* unsolicited event for jack sensing */ |
2438 | static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) | 2412 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) |
2439 | { | 2413 | { |
2440 | snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); | 2414 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); |
2441 | switch (res >> 26) { | 2415 | switch (res >> 26) { |
2442 | case CONEXANT_HP_EVENT: | 2416 | case CONEXANT_HP_EVENT: |
2443 | cxt5066_hp_automute(codec); | 2417 | cxt5066_hp_automute(codec); |
2444 | break; | 2418 | break; |
2445 | case CONEXANT_MIC_EVENT: | 2419 | case CONEXANT_MIC_EVENT: |
2446 | cxt5066_thinkpad_automic(codec); | 2420 | cxt5066_automic(codec); |
2447 | break; | 2421 | break; |
2448 | } | 2422 | } |
2449 | } | 2423 | } |
2450 | 2424 | ||
2425 | |||
2451 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2426 | static const struct hda_input_mux cxt5066_analog_mic_boost = { |
2452 | .num_items = 5, | 2427 | .num_items = 5, |
2453 | .items = { | 2428 | .items = { |
@@ -2621,7 +2596,28 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | |||
2621 | spec->recording = 0; | 2596 | spec->recording = 0; |
2622 | } | 2597 | } |
2623 | 2598 | ||
2624 | static struct hda_input_mux cxt5066_capture_source = { | 2599 | static void conexant_check_dig_outs(struct hda_codec *codec, |
2600 | const hda_nid_t *dig_pins, | ||
2601 | int num_pins) | ||
2602 | { | ||
2603 | struct conexant_spec *spec = codec->spec; | ||
2604 | hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; | ||
2605 | int i; | ||
2606 | |||
2607 | for (i = 0; i < num_pins; i++, dig_pins++) { | ||
2608 | unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); | ||
2609 | if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) | ||
2610 | continue; | ||
2611 | if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) | ||
2612 | continue; | ||
2613 | if (spec->slave_dig_outs[0]) | ||
2614 | nid_loc++; | ||
2615 | else | ||
2616 | nid_loc = spec->slave_dig_outs; | ||
2617 | } | ||
2618 | } | ||
2619 | |||
2620 | static const struct hda_input_mux cxt5066_capture_source = { | ||
2625 | .num_items = 4, | 2621 | .num_items = 4, |
2626 | .items = { | 2622 | .items = { |
2627 | { "Mic B", 0 }, | 2623 | { "Mic B", 0 }, |
@@ -2631,7 +2627,7 @@ static struct hda_input_mux cxt5066_capture_source = { | |||
2631 | }, | 2627 | }, |
2632 | }; | 2628 | }; |
2633 | 2629 | ||
2634 | static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { | 2630 | static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = { |
2635 | .ops = &snd_hda_bind_vol, | 2631 | .ops = &snd_hda_bind_vol, |
2636 | .values = { | 2632 | .values = { |
2637 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), | 2633 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), |
@@ -2640,7 +2636,7 @@ static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { | |||
2640 | }, | 2636 | }, |
2641 | }; | 2637 | }; |
2642 | 2638 | ||
2643 | static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { | 2639 | static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = { |
2644 | .ops = &snd_hda_bind_sw, | 2640 | .ops = &snd_hda_bind_sw, |
2645 | .values = { | 2641 | .values = { |
2646 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), | 2642 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), |
@@ -2649,12 +2645,12 @@ static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { | |||
2649 | }, | 2645 | }, |
2650 | }; | 2646 | }; |
2651 | 2647 | ||
2652 | static struct snd_kcontrol_new cxt5066_mixer_master[] = { | 2648 | static const struct snd_kcontrol_new cxt5066_mixer_master[] = { |
2653 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | 2649 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), |
2654 | {} | 2650 | {} |
2655 | }; | 2651 | }; |
2656 | 2652 | ||
2657 | static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | 2653 | static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { |
2658 | { | 2654 | { |
2659 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2655 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2660 | .name = "Master Playback Volume", | 2656 | .name = "Master Playback Volume", |
@@ -2673,7 +2669,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
2673 | {} | 2669 | {} |
2674 | }; | 2670 | }; |
2675 | 2671 | ||
2676 | static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | 2672 | static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { |
2677 | { | 2673 | { |
2678 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2674 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2679 | .name = "DC Mode Enable Switch", | 2675 | .name = "DC Mode Enable Switch", |
@@ -2691,7 +2687,7 @@ static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | |||
2691 | {} | 2687 | {} |
2692 | }; | 2688 | }; |
2693 | 2689 | ||
2694 | static struct snd_kcontrol_new cxt5066_mixers[] = { | 2690 | static const struct snd_kcontrol_new cxt5066_mixers[] = { |
2695 | { | 2691 | { |
2696 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2692 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2697 | .name = "Master Playback Switch", | 2693 | .name = "Master Playback Switch", |
@@ -2714,10 +2710,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2714 | {} | 2710 | {} |
2715 | }; | 2711 | }; |
2716 | 2712 | ||
2717 | static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | 2713 | static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = { |
2718 | { | 2714 | { |
2719 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2720 | .name = "Int Mic Boost Capture Enum", | 2716 | .name = "Internal Mic Boost Capture Enum", |
2721 | .info = cxt5066_mic_boost_mux_enum_info, | 2717 | .info = cxt5066_mic_boost_mux_enum_info, |
2722 | .get = cxt5066_mic_boost_mux_enum_get, | 2718 | .get = cxt5066_mic_boost_mux_enum_get, |
2723 | .put = cxt5066_mic_boost_mux_enum_put, | 2719 | .put = cxt5066_mic_boost_mux_enum_put, |
@@ -2726,7 +2722,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | |||
2726 | {} | 2722 | {} |
2727 | }; | 2723 | }; |
2728 | 2724 | ||
2729 | static struct hda_verb cxt5066_init_verbs[] = { | 2725 | static const struct hda_verb cxt5066_init_verbs[] = { |
2730 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | 2726 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ |
2731 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | 2727 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ |
2732 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | 2728 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ |
@@ -2781,7 +2777,7 @@ static struct hda_verb cxt5066_init_verbs[] = { | |||
2781 | { } /* end */ | 2777 | { } /* end */ |
2782 | }; | 2778 | }; |
2783 | 2779 | ||
2784 | static struct hda_verb cxt5066_init_verbs_olpc[] = { | 2780 | static const struct hda_verb cxt5066_init_verbs_olpc[] = { |
2785 | /* Port A: headphones */ | 2781 | /* Port A: headphones */ |
2786 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 2782 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
2787 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2783 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
@@ -2842,7 +2838,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2842 | { } /* end */ | 2838 | { } /* end */ |
2843 | }; | 2839 | }; |
2844 | 2840 | ||
2845 | static struct hda_verb cxt5066_init_verbs_vostro[] = { | 2841 | static const struct hda_verb cxt5066_init_verbs_vostro[] = { |
2846 | /* Port A: headphones */ | 2842 | /* Port A: headphones */ |
2847 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2843 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
2848 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2844 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
@@ -2903,7 +2899,7 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = { | |||
2903 | { } /* end */ | 2899 | { } /* end */ |
2904 | }; | 2900 | }; |
2905 | 2901 | ||
2906 | static struct hda_verb cxt5066_init_verbs_ideapad[] = { | 2902 | static const struct hda_verb cxt5066_init_verbs_ideapad[] = { |
2907 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | 2903 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ |
2908 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | 2904 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ |
2909 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | 2905 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ |
@@ -2943,7 +2939,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { | |||
2943 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 2939 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2944 | 2940 | ||
2945 | /* internal microphone */ | 2941 | /* internal microphone */ |
2946 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ | 2942 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ |
2947 | 2943 | ||
2948 | /* EAPD */ | 2944 | /* EAPD */ |
2949 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 2945 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
@@ -2953,7 +2949,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = { | |||
2953 | { } /* end */ | 2949 | { } /* end */ |
2954 | }; | 2950 | }; |
2955 | 2951 | ||
2956 | static struct hda_verb cxt5066_init_verbs_thinkpad[] = { | 2952 | static const struct hda_verb cxt5066_init_verbs_thinkpad[] = { |
2957 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | 2953 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ |
2958 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ | 2954 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ |
2959 | 2955 | ||
@@ -2998,7 +2994,7 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = { | |||
2998 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 2994 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2999 | 2995 | ||
3000 | /* internal microphone */ | 2996 | /* internal microphone */ |
3001 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ | 2997 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */ |
3002 | 2998 | ||
3003 | /* EAPD */ | 2999 | /* EAPD */ |
3004 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 3000 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
@@ -3011,13 +3007,13 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = { | |||
3011 | { } /* end */ | 3007 | { } /* end */ |
3012 | }; | 3008 | }; |
3013 | 3009 | ||
3014 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 3010 | static const struct hda_verb cxt5066_init_verbs_portd_lo[] = { |
3015 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 3011 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
3016 | { } /* end */ | 3012 | { } /* end */ |
3017 | }; | 3013 | }; |
3018 | 3014 | ||
3019 | 3015 | ||
3020 | static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { | 3016 | static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { |
3021 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, | 3017 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, |
3022 | {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}, |
3023 | {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}, |
@@ -3027,20 +3023,11 @@ static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { | |||
3027 | /* initialize jack-sensing, too */ | 3023 | /* initialize jack-sensing, too */ |
3028 | static int cxt5066_init(struct hda_codec *codec) | 3024 | static int cxt5066_init(struct hda_codec *codec) |
3029 | { | 3025 | { |
3030 | struct conexant_spec *spec = codec->spec; | ||
3031 | |||
3032 | snd_printdd("CXT5066: init\n"); | 3026 | snd_printdd("CXT5066: init\n"); |
3033 | conexant_init(codec); | 3027 | conexant_init(codec); |
3034 | if (codec->patch_ops.unsol_event) { | 3028 | if (codec->patch_ops.unsol_event) { |
3035 | cxt5066_hp_automute(codec); | 3029 | cxt5066_hp_automute(codec); |
3036 | if (spec->dell_vostro) | 3030 | cxt5066_automic(codec); |
3037 | cxt5066_vostro_automic(codec); | ||
3038 | else if (spec->ideapad) | ||
3039 | cxt5066_ideapad_automic(codec); | ||
3040 | else if (spec->thinkpad) | ||
3041 | cxt5066_thinkpad_automic(codec); | ||
3042 | else if (spec->hp_laptop) | ||
3043 | cxt5066_hp_laptop_automic(codec); | ||
3044 | } | 3031 | } |
3045 | cxt5066_set_mic_boost(codec); | 3032 | cxt5066_set_mic_boost(codec); |
3046 | return 0; | 3033 | return 0; |
@@ -3065,45 +3052,58 @@ enum { | |||
3065 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ | 3052 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ |
3066 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ | 3053 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ |
3067 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ | 3054 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ |
3068 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ | 3055 | CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ |
3069 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ | 3056 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ |
3070 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ | 3057 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ |
3058 | CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ | ||
3071 | CXT5066_HP_LAPTOP, /* HP Laptop */ | 3059 | CXT5066_HP_LAPTOP, /* HP Laptop */ |
3060 | CXT5066_AUTO, /* BIOS auto-parser */ | ||
3072 | CXT5066_MODELS | 3061 | CXT5066_MODELS |
3073 | }; | 3062 | }; |
3074 | 3063 | ||
3075 | static const char *cxt5066_models[CXT5066_MODELS] = { | 3064 | static const char * const cxt5066_models[CXT5066_MODELS] = { |
3076 | [CXT5066_LAPTOP] = "laptop", | 3065 | [CXT5066_LAPTOP] = "laptop", |
3077 | [CXT5066_DELL_LAPTOP] = "dell-laptop", | 3066 | [CXT5066_DELL_LAPTOP] = "dell-laptop", |
3078 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", | 3067 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", |
3079 | [CXT5066_DELL_VOSTO] = "dell-vostro", | 3068 | [CXT5066_DELL_VOSTRO] = "dell-vostro", |
3080 | [CXT5066_IDEAPAD] = "ideapad", | 3069 | [CXT5066_IDEAPAD] = "ideapad", |
3081 | [CXT5066_THINKPAD] = "thinkpad", | 3070 | [CXT5066_THINKPAD] = "thinkpad", |
3071 | [CXT5066_ASUS] = "asus", | ||
3082 | [CXT5066_HP_LAPTOP] = "hp-laptop", | 3072 | [CXT5066_HP_LAPTOP] = "hp-laptop", |
3073 | [CXT5066_AUTO] = "auto", | ||
3083 | }; | 3074 | }; |
3084 | 3075 | ||
3085 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 3076 | static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
3086 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | 3077 | SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT5066_AUTO), |
3087 | CXT5066_LAPTOP), | 3078 | SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD), |
3088 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", | 3079 | SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), |
3089 | CXT5066_DELL_LAPTOP), | 3080 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), |
3090 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | 3081 | SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), |
3091 | SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), | 3082 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), |
3092 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), | ||
3093 | SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), | 3083 | SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), |
3084 | SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), | ||
3085 | SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), | ||
3094 | SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), | 3086 | SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), |
3087 | SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), | ||
3088 | SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), | ||
3089 | SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), | ||
3095 | SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), | 3090 | SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), |
3096 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), | 3091 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), |
3097 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), | 3092 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), |
3093 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | ||
3094 | CXT5066_LAPTOP), | ||
3095 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | ||
3098 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), | 3096 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), |
3099 | SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), | 3097 | SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), |
3100 | SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), | 3098 | SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), |
3101 | SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), | ||
3102 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), | 3099 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), |
3103 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), | 3100 | SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), |
3104 | SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), | 3101 | SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), |
3105 | SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), | 3102 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), |
3106 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), | 3103 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), |
3104 | SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO), | ||
3105 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ | ||
3106 | SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO), | ||
3107 | {} | 3107 | {} |
3108 | }; | 3108 | }; |
3109 | 3109 | ||
@@ -3112,6 +3112,15 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3112 | struct conexant_spec *spec; | 3112 | struct conexant_spec *spec; |
3113 | int board_config; | 3113 | int board_config; |
3114 | 3114 | ||
3115 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | ||
3116 | cxt5066_models, cxt5066_cfg_tbl); | ||
3117 | #if 0 /* use the old method just for safety */ | ||
3118 | if (board_config < 0) | ||
3119 | board_config = CXT5066_AUTO; | ||
3120 | #endif | ||
3121 | if (board_config == CXT5066_AUTO) | ||
3122 | return patch_conexant_auto(codec); | ||
3123 | |||
3115 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3124 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
3116 | if (!spec) | 3125 | if (!spec) |
3117 | return -ENOMEM; | 3126 | return -ENOMEM; |
@@ -3124,7 +3133,8 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3124 | spec->multiout.max_channels = 2; | 3133 | spec->multiout.max_channels = 2; |
3125 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); | 3134 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); |
3126 | spec->multiout.dac_nids = cxt5066_dac_nids; | 3135 | spec->multiout.dac_nids = cxt5066_dac_nids; |
3127 | spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; | 3136 | conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, |
3137 | ARRAY_SIZE(cxt5066_digout_pin_nids)); | ||
3128 | spec->num_adc_nids = 1; | 3138 | spec->num_adc_nids = 1; |
3129 | spec->adc_nids = cxt5066_adc_nids; | 3139 | spec->adc_nids = cxt5066_adc_nids; |
3130 | spec->capsrc_nids = cxt5066_capsrc_nids; | 3140 | spec->capsrc_nids = cxt5066_capsrc_nids; |
@@ -3141,8 +3151,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3141 | 3151 | ||
3142 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); | 3152 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); |
3143 | 3153 | ||
3144 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | ||
3145 | cxt5066_models, cxt5066_cfg_tbl); | ||
3146 | switch (board_config) { | 3154 | switch (board_config) { |
3147 | default: | 3155 | default: |
3148 | case CXT5066_LAPTOP: | 3156 | case CXT5066_LAPTOP: |
@@ -3158,17 +3166,20 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3158 | spec->num_init_verbs++; | 3166 | spec->num_init_verbs++; |
3159 | spec->dell_automute = 1; | 3167 | spec->dell_automute = 1; |
3160 | break; | 3168 | break; |
3169 | case CXT5066_ASUS: | ||
3161 | case CXT5066_HP_LAPTOP: | 3170 | case CXT5066_HP_LAPTOP: |
3162 | codec->patch_ops.init = cxt5066_init; | 3171 | codec->patch_ops.init = cxt5066_init; |
3163 | codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; | 3172 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
3164 | spec->init_verbs[spec->num_init_verbs] = | 3173 | spec->init_verbs[spec->num_init_verbs] = |
3165 | cxt5066_init_verbs_hp_laptop; | 3174 | cxt5066_init_verbs_hp_laptop; |
3166 | spec->num_init_verbs++; | 3175 | spec->num_init_verbs++; |
3167 | spec->hp_laptop = 1; | 3176 | spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; |
3177 | spec->asus = board_config == CXT5066_ASUS; | ||
3168 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | 3178 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; |
3169 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3179 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
3170 | /* no S/PDIF out */ | 3180 | /* no S/PDIF out */ |
3171 | spec->multiout.dig_out_nid = 0; | 3181 | if (board_config == CXT5066_HP_LAPTOP) |
3182 | spec->multiout.dig_out_nid = 0; | ||
3172 | /* input source automatically selected */ | 3183 | /* input source automatically selected */ |
3173 | spec->input_mux = NULL; | 3184 | spec->input_mux = NULL; |
3174 | spec->port_d_mode = 0; | 3185 | spec->port_d_mode = 0; |
@@ -3196,9 +3207,9 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3196 | spec->capture_prepare = cxt5066_olpc_capture_prepare; | 3207 | spec->capture_prepare = cxt5066_olpc_capture_prepare; |
3197 | spec->capture_cleanup = cxt5066_olpc_capture_cleanup; | 3208 | spec->capture_cleanup = cxt5066_olpc_capture_cleanup; |
3198 | break; | 3209 | break; |
3199 | case CXT5066_DELL_VOSTO: | 3210 | case CXT5066_DELL_VOSTRO: |
3200 | codec->patch_ops.init = cxt5066_init; | 3211 | codec->patch_ops.init = cxt5066_init; |
3201 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | 3212 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
3202 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | 3213 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; |
3203 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 3214 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
3204 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3215 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
@@ -3215,7 +3226,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3215 | break; | 3226 | break; |
3216 | case CXT5066_IDEAPAD: | 3227 | case CXT5066_IDEAPAD: |
3217 | codec->patch_ops.init = cxt5066_init; | 3228 | codec->patch_ops.init = cxt5066_init; |
3218 | codec->patch_ops.unsol_event = cxt5066_ideapad_event; | 3229 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
3219 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | 3230 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; |
3220 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3231 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
3221 | spec->init_verbs[0] = cxt5066_init_verbs_ideapad; | 3232 | spec->init_verbs[0] = cxt5066_init_verbs_ideapad; |
@@ -3231,7 +3242,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3231 | break; | 3242 | break; |
3232 | case CXT5066_THINKPAD: | 3243 | case CXT5066_THINKPAD: |
3233 | codec->patch_ops.init = cxt5066_init; | 3244 | codec->patch_ops.init = cxt5066_init; |
3234 | codec->patch_ops.unsol_event = cxt5066_thinkpad_event; | 3245 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
3235 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | 3246 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; |
3236 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3247 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
3237 | spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; | 3248 | spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; |
@@ -3254,9 +3265,1117 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3254 | } | 3265 | } |
3255 | 3266 | ||
3256 | /* | 3267 | /* |
3268 | * Automatic parser for CX20641 & co | ||
3269 | */ | ||
3270 | |||
3271 | static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
3272 | struct hda_codec *codec, | ||
3273 | unsigned int stream_tag, | ||
3274 | unsigned int format, | ||
3275 | struct snd_pcm_substream *substream) | ||
3276 | { | ||
3277 | struct conexant_spec *spec = codec->spec; | ||
3278 | hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc; | ||
3279 | if (spec->adc_switching) { | ||
3280 | spec->cur_adc = adc; | ||
3281 | spec->cur_adc_stream_tag = stream_tag; | ||
3282 | spec->cur_adc_format = format; | ||
3283 | } | ||
3284 | snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); | ||
3285 | return 0; | ||
3286 | } | ||
3287 | |||
3288 | static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
3289 | struct hda_codec *codec, | ||
3290 | struct snd_pcm_substream *substream) | ||
3291 | { | ||
3292 | struct conexant_spec *spec = codec->spec; | ||
3293 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
3294 | spec->cur_adc = 0; | ||
3295 | return 0; | ||
3296 | } | ||
3297 | |||
3298 | static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { | ||
3299 | .substreams = 1, | ||
3300 | .channels_min = 2, | ||
3301 | .channels_max = 2, | ||
3302 | .nid = 0, /* fill later */ | ||
3303 | .ops = { | ||
3304 | .prepare = cx_auto_capture_pcm_prepare, | ||
3305 | .cleanup = cx_auto_capture_pcm_cleanup | ||
3306 | }, | ||
3307 | }; | ||
3308 | |||
3309 | static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; | ||
3310 | |||
3311 | /* get the connection index of @nid in the widget @mux */ | ||
3312 | static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, | ||
3313 | hda_nid_t nid) | ||
3314 | { | ||
3315 | hda_nid_t conn[HDA_MAX_NUM_INPUTS]; | ||
3316 | int i, nums; | ||
3317 | |||
3318 | nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); | ||
3319 | for (i = 0; i < nums; i++) | ||
3320 | if (conn[i] == nid) | ||
3321 | return i; | ||
3322 | return -1; | ||
3323 | } | ||
3324 | |||
3325 | /* get an unassigned DAC from the given list. | ||
3326 | * Return the nid if found and reduce the DAC list, or return zero if | ||
3327 | * not found | ||
3328 | */ | ||
3329 | static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin, | ||
3330 | hda_nid_t *dacs, int *num_dacs) | ||
3331 | { | ||
3332 | int i, nums = *num_dacs; | ||
3333 | hda_nid_t ret = 0; | ||
3334 | |||
3335 | for (i = 0; i < nums; i++) { | ||
3336 | if (get_connection_index(codec, pin, dacs[i]) >= 0) { | ||
3337 | ret = dacs[i]; | ||
3338 | break; | ||
3339 | } | ||
3340 | } | ||
3341 | if (!ret) | ||
3342 | return 0; | ||
3343 | if (--nums > 0) | ||
3344 | memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t)); | ||
3345 | *num_dacs = nums; | ||
3346 | return ret; | ||
3347 | } | ||
3348 | |||
3349 | #define MAX_AUTO_DACS 5 | ||
3350 | |||
3351 | /* fill analog DAC list from the widget tree */ | ||
3352 | static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) | ||
3353 | { | ||
3354 | hda_nid_t nid, end_nid; | ||
3355 | int nums = 0; | ||
3356 | |||
3357 | end_nid = codec->start_nid + codec->num_nodes; | ||
3358 | for (nid = codec->start_nid; nid < end_nid; nid++) { | ||
3359 | unsigned int wcaps = get_wcaps(codec, nid); | ||
3360 | unsigned int type = get_wcaps_type(wcaps); | ||
3361 | if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) { | ||
3362 | dacs[nums++] = nid; | ||
3363 | if (nums >= MAX_AUTO_DACS) | ||
3364 | break; | ||
3365 | } | ||
3366 | } | ||
3367 | return nums; | ||
3368 | } | ||
3369 | |||
3370 | /* fill pin_dac_pair list from the pin and dac list */ | ||
3371 | static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins, | ||
3372 | int num_pins, hda_nid_t *dacs, int *rest, | ||
3373 | struct pin_dac_pair *filled, int type) | ||
3374 | { | ||
3375 | int i, nums; | ||
3376 | |||
3377 | nums = 0; | ||
3378 | for (i = 0; i < num_pins; i++) { | ||
3379 | filled[nums].pin = pins[i]; | ||
3380 | filled[nums].type = type; | ||
3381 | filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); | ||
3382 | nums++; | ||
3383 | } | ||
3384 | return nums; | ||
3385 | } | ||
3386 | |||
3387 | /* parse analog output paths */ | ||
3388 | static void cx_auto_parse_output(struct hda_codec *codec) | ||
3389 | { | ||
3390 | struct conexant_spec *spec = codec->spec; | ||
3391 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3392 | hda_nid_t dacs[MAX_AUTO_DACS]; | ||
3393 | int i, j, nums, rest; | ||
3394 | |||
3395 | rest = fill_cx_auto_dacs(codec, dacs); | ||
3396 | /* parse all analog output pins */ | ||
3397 | nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs, | ||
3398 | dacs, &rest, spec->dac_info, | ||
3399 | AUTO_PIN_LINE_OUT); | ||
3400 | nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, | ||
3401 | dacs, &rest, spec->dac_info + nums, | ||
3402 | AUTO_PIN_HP_OUT); | ||
3403 | nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, | ||
3404 | dacs, &rest, spec->dac_info + nums, | ||
3405 | AUTO_PIN_SPEAKER_OUT); | ||
3406 | spec->dac_info_filled = nums; | ||
3407 | /* fill multiout struct */ | ||
3408 | for (i = 0; i < nums; i++) { | ||
3409 | hda_nid_t dac = spec->dac_info[i].dac; | ||
3410 | if (!dac) | ||
3411 | continue; | ||
3412 | switch (spec->dac_info[i].type) { | ||
3413 | case AUTO_PIN_LINE_OUT: | ||
3414 | spec->private_dac_nids[spec->multiout.num_dacs] = dac; | ||
3415 | spec->multiout.num_dacs++; | ||
3416 | break; | ||
3417 | case AUTO_PIN_HP_OUT: | ||
3418 | case AUTO_PIN_SPEAKER_OUT: | ||
3419 | if (!spec->multiout.hp_nid) { | ||
3420 | spec->multiout.hp_nid = dac; | ||
3421 | break; | ||
3422 | } | ||
3423 | for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++) | ||
3424 | if (!spec->multiout.extra_out_nid[j]) { | ||
3425 | spec->multiout.extra_out_nid[j] = dac; | ||
3426 | break; | ||
3427 | } | ||
3428 | break; | ||
3429 | } | ||
3430 | } | ||
3431 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
3432 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
3433 | |||
3434 | for (i = 0; i < cfg->hp_outs; i++) { | ||
3435 | if (is_jack_detectable(codec, cfg->hp_pins[i])) { | ||
3436 | spec->auto_mute = 1; | ||
3437 | break; | ||
3438 | } | ||
3439 | } | ||
3440 | if (spec->auto_mute && | ||
3441 | cfg->line_out_pins[0] && | ||
3442 | cfg->line_out_type != AUTO_PIN_SPEAKER_OUT && | ||
3443 | cfg->line_out_pins[0] != cfg->hp_pins[0] && | ||
3444 | cfg->line_out_pins[0] != cfg->speaker_pins[0]) { | ||
3445 | for (i = 0; i < cfg->line_outs; i++) { | ||
3446 | if (is_jack_detectable(codec, cfg->line_out_pins[i])) { | ||
3447 | spec->detect_line = 1; | ||
3448 | break; | ||
3449 | } | ||
3450 | } | ||
3451 | spec->automute_lines = spec->detect_line; | ||
3452 | } | ||
3453 | |||
3454 | spec->vmaster_nid = spec->private_dac_nids[0]; | ||
3455 | } | ||
3456 | |||
3457 | static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, | ||
3458 | hda_nid_t *pins, bool on); | ||
3459 | |||
3460 | static void do_automute(struct hda_codec *codec, int num_pins, | ||
3461 | hda_nid_t *pins, bool on) | ||
3462 | { | ||
3463 | int i; | ||
3464 | for (i = 0; i < num_pins; i++) | ||
3465 | snd_hda_codec_write(codec, pins[i], 0, | ||
3466 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3467 | on ? PIN_OUT : 0); | ||
3468 | cx_auto_turn_eapd(codec, num_pins, pins, on); | ||
3469 | } | ||
3470 | |||
3471 | static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | ||
3472 | { | ||
3473 | int i, present = 0; | ||
3474 | |||
3475 | for (i = 0; i < num_pins; i++) { | ||
3476 | hda_nid_t nid = pins[i]; | ||
3477 | if (!nid || !is_jack_detectable(codec, nid)) | ||
3478 | break; | ||
3479 | snd_hda_input_jack_report(codec, nid); | ||
3480 | present |= snd_hda_jack_detect(codec, nid); | ||
3481 | } | ||
3482 | return present; | ||
3483 | } | ||
3484 | |||
3485 | /* auto-mute/unmute speaker and line outs according to headphone jack */ | ||
3486 | static void cx_auto_update_speakers(struct hda_codec *codec) | ||
3487 | { | ||
3488 | struct conexant_spec *spec = codec->spec; | ||
3489 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3490 | int on = 1; | ||
3491 | |||
3492 | /* turn on HP EAPD when HP jacks are present */ | ||
3493 | if (spec->auto_mute) | ||
3494 | on = spec->hp_present; | ||
3495 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); | ||
3496 | /* mute speakers in auto-mode if HP or LO jacks are plugged */ | ||
3497 | if (spec->auto_mute) | ||
3498 | on = !(spec->hp_present || | ||
3499 | (spec->detect_line && spec->line_present)); | ||
3500 | do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on); | ||
3501 | |||
3502 | /* toggle line-out mutes if needed, too */ | ||
3503 | /* if LO is a copy of either HP or Speaker, don't need to handle it */ | ||
3504 | if (cfg->line_out_pins[0] == cfg->hp_pins[0] || | ||
3505 | cfg->line_out_pins[0] == cfg->speaker_pins[0]) | ||
3506 | return; | ||
3507 | if (spec->auto_mute) { | ||
3508 | /* mute LO in auto-mode when HP jack is present */ | ||
3509 | if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT || | ||
3510 | spec->automute_lines) | ||
3511 | on = !spec->hp_present; | ||
3512 | else | ||
3513 | on = 1; | ||
3514 | } | ||
3515 | do_automute(codec, cfg->line_outs, cfg->line_out_pins, on); | ||
3516 | } | ||
3517 | |||
3518 | static void cx_auto_hp_automute(struct hda_codec *codec) | ||
3519 | { | ||
3520 | struct conexant_spec *spec = codec->spec; | ||
3521 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3522 | |||
3523 | if (!spec->auto_mute) | ||
3524 | return; | ||
3525 | spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); | ||
3526 | cx_auto_update_speakers(codec); | ||
3527 | } | ||
3528 | |||
3529 | static void cx_auto_line_automute(struct hda_codec *codec) | ||
3530 | { | ||
3531 | struct conexant_spec *spec = codec->spec; | ||
3532 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3533 | |||
3534 | if (!spec->auto_mute || !spec->detect_line) | ||
3535 | return; | ||
3536 | spec->line_present = detect_jacks(codec, cfg->line_outs, | ||
3537 | cfg->line_out_pins); | ||
3538 | cx_auto_update_speakers(codec); | ||
3539 | } | ||
3540 | |||
3541 | static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, | ||
3542 | struct snd_ctl_elem_info *uinfo) | ||
3543 | { | ||
3544 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3545 | struct conexant_spec *spec = codec->spec; | ||
3546 | static const char * const texts2[] = { | ||
3547 | "Disabled", "Enabled" | ||
3548 | }; | ||
3549 | static const char * const texts3[] = { | ||
3550 | "Disabled", "Speaker Only", "Line-Out+Speaker" | ||
3551 | }; | ||
3552 | const char * const *texts; | ||
3553 | |||
3554 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
3555 | uinfo->count = 1; | ||
3556 | if (spec->automute_hp_lo) { | ||
3557 | uinfo->value.enumerated.items = 3; | ||
3558 | texts = texts3; | ||
3559 | } else { | ||
3560 | uinfo->value.enumerated.items = 2; | ||
3561 | texts = texts2; | ||
3562 | } | ||
3563 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
3564 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
3565 | strcpy(uinfo->value.enumerated.name, | ||
3566 | texts[uinfo->value.enumerated.item]); | ||
3567 | return 0; | ||
3568 | } | ||
3569 | |||
3570 | static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, | ||
3571 | struct snd_ctl_elem_value *ucontrol) | ||
3572 | { | ||
3573 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3574 | struct conexant_spec *spec = codec->spec; | ||
3575 | unsigned int val; | ||
3576 | if (!spec->auto_mute) | ||
3577 | val = 0; | ||
3578 | else if (!spec->automute_lines) | ||
3579 | val = 1; | ||
3580 | else | ||
3581 | val = 2; | ||
3582 | ucontrol->value.enumerated.item[0] = val; | ||
3583 | return 0; | ||
3584 | } | ||
3585 | |||
3586 | static int cx_automute_mode_put(struct snd_kcontrol *kcontrol, | ||
3587 | struct snd_ctl_elem_value *ucontrol) | ||
3588 | { | ||
3589 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3590 | struct conexant_spec *spec = codec->spec; | ||
3591 | |||
3592 | switch (ucontrol->value.enumerated.item[0]) { | ||
3593 | case 0: | ||
3594 | if (!spec->auto_mute) | ||
3595 | return 0; | ||
3596 | spec->auto_mute = 0; | ||
3597 | break; | ||
3598 | case 1: | ||
3599 | if (spec->auto_mute && !spec->automute_lines) | ||
3600 | return 0; | ||
3601 | spec->auto_mute = 1; | ||
3602 | spec->automute_lines = 0; | ||
3603 | break; | ||
3604 | case 2: | ||
3605 | if (!spec->automute_hp_lo) | ||
3606 | return -EINVAL; | ||
3607 | if (spec->auto_mute && spec->automute_lines) | ||
3608 | return 0; | ||
3609 | spec->auto_mute = 1; | ||
3610 | spec->automute_lines = 1; | ||
3611 | break; | ||
3612 | default: | ||
3613 | return -EINVAL; | ||
3614 | } | ||
3615 | cx_auto_update_speakers(codec); | ||
3616 | return 1; | ||
3617 | } | ||
3618 | |||
3619 | static const struct snd_kcontrol_new cx_automute_mode_enum[] = { | ||
3620 | { | ||
3621 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3622 | .name = "Auto-Mute Mode", | ||
3623 | .info = cx_automute_mode_info, | ||
3624 | .get = cx_automute_mode_get, | ||
3625 | .put = cx_automute_mode_put, | ||
3626 | }, | ||
3627 | { } | ||
3628 | }; | ||
3629 | |||
3630 | static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
3631 | struct snd_ctl_elem_info *uinfo) | ||
3632 | { | ||
3633 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3634 | struct conexant_spec *spec = codec->spec; | ||
3635 | |||
3636 | return snd_hda_input_mux_info(&spec->private_imux, uinfo); | ||
3637 | } | ||
3638 | |||
3639 | static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
3640 | struct snd_ctl_elem_value *ucontrol) | ||
3641 | { | ||
3642 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3643 | struct conexant_spec *spec = codec->spec; | ||
3644 | |||
3645 | ucontrol->value.enumerated.item[0] = spec->cur_mux[0]; | ||
3646 | return 0; | ||
3647 | } | ||
3648 | |||
3649 | /* look for the route the given pin from mux and return the index; | ||
3650 | * if do_select is set, actually select the route. | ||
3651 | */ | ||
3652 | static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux, | ||
3653 | hda_nid_t pin, hda_nid_t *srcp, | ||
3654 | bool do_select, int depth) | ||
3655 | { | ||
3656 | hda_nid_t conn[HDA_MAX_NUM_INPUTS]; | ||
3657 | int i, nums; | ||
3658 | |||
3659 | switch (get_wcaps_type(get_wcaps(codec, mux))) { | ||
3660 | case AC_WID_AUD_IN: | ||
3661 | case AC_WID_AUD_SEL: | ||
3662 | case AC_WID_AUD_MIX: | ||
3663 | break; | ||
3664 | default: | ||
3665 | return -1; | ||
3666 | } | ||
3667 | |||
3668 | nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); | ||
3669 | for (i = 0; i < nums; i++) | ||
3670 | if (conn[i] == pin) { | ||
3671 | if (do_select) | ||
3672 | snd_hda_codec_write(codec, mux, 0, | ||
3673 | AC_VERB_SET_CONNECT_SEL, i); | ||
3674 | if (srcp) | ||
3675 | *srcp = mux; | ||
3676 | return i; | ||
3677 | } | ||
3678 | depth++; | ||
3679 | if (depth == 2) | ||
3680 | return -1; | ||
3681 | for (i = 0; i < nums; i++) { | ||
3682 | int ret = __select_input_connection(codec, conn[i], pin, srcp, | ||
3683 | do_select, depth); | ||
3684 | if (ret >= 0) { | ||
3685 | if (do_select) | ||
3686 | snd_hda_codec_write(codec, mux, 0, | ||
3687 | AC_VERB_SET_CONNECT_SEL, i); | ||
3688 | return i; | ||
3689 | } | ||
3690 | } | ||
3691 | return -1; | ||
3692 | } | ||
3693 | |||
3694 | static void select_input_connection(struct hda_codec *codec, hda_nid_t mux, | ||
3695 | hda_nid_t pin) | ||
3696 | { | ||
3697 | __select_input_connection(codec, mux, pin, NULL, true, 0); | ||
3698 | } | ||
3699 | |||
3700 | static int get_input_connection(struct hda_codec *codec, hda_nid_t mux, | ||
3701 | hda_nid_t pin) | ||
3702 | { | ||
3703 | return __select_input_connection(codec, mux, pin, NULL, false, 0); | ||
3704 | } | ||
3705 | |||
3706 | static int cx_auto_mux_enum_update(struct hda_codec *codec, | ||
3707 | const struct hda_input_mux *imux, | ||
3708 | unsigned int idx) | ||
3709 | { | ||
3710 | struct conexant_spec *spec = codec->spec; | ||
3711 | hda_nid_t adc; | ||
3712 | int changed = 1; | ||
3713 | |||
3714 | if (!imux->num_items) | ||
3715 | return 0; | ||
3716 | if (idx >= imux->num_items) | ||
3717 | idx = imux->num_items - 1; | ||
3718 | if (spec->cur_mux[0] == idx) | ||
3719 | changed = 0; | ||
3720 | adc = spec->imux_info[idx].adc; | ||
3721 | select_input_connection(codec, spec->imux_info[idx].adc, | ||
3722 | spec->imux_info[idx].pin); | ||
3723 | if (spec->cur_adc && spec->cur_adc != adc) { | ||
3724 | /* stream is running, let's swap the current ADC */ | ||
3725 | __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); | ||
3726 | spec->cur_adc = adc; | ||
3727 | snd_hda_codec_setup_stream(codec, adc, | ||
3728 | spec->cur_adc_stream_tag, 0, | ||
3729 | spec->cur_adc_format); | ||
3730 | } | ||
3731 | spec->cur_mux[0] = idx; | ||
3732 | return changed; | ||
3733 | } | ||
3734 | |||
3735 | static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
3736 | struct snd_ctl_elem_value *ucontrol) | ||
3737 | { | ||
3738 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3739 | struct conexant_spec *spec = codec->spec; | ||
3740 | |||
3741 | return cx_auto_mux_enum_update(codec, &spec->private_imux, | ||
3742 | ucontrol->value.enumerated.item[0]); | ||
3743 | } | ||
3744 | |||
3745 | static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { | ||
3746 | { | ||
3747 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3748 | .name = "Capture Source", | ||
3749 | .info = cx_auto_mux_enum_info, | ||
3750 | .get = cx_auto_mux_enum_get, | ||
3751 | .put = cx_auto_mux_enum_put | ||
3752 | }, | ||
3753 | {} | ||
3754 | }; | ||
3755 | |||
3756 | static bool select_automic(struct hda_codec *codec, int idx, bool detect) | ||
3757 | { | ||
3758 | struct conexant_spec *spec = codec->spec; | ||
3759 | if (idx < 0) | ||
3760 | return false; | ||
3761 | if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) | ||
3762 | return false; | ||
3763 | cx_auto_mux_enum_update(codec, &spec->private_imux, idx); | ||
3764 | return true; | ||
3765 | } | ||
3766 | |||
3767 | /* automatic switch internal and external mic */ | ||
3768 | static void cx_auto_automic(struct hda_codec *codec) | ||
3769 | { | ||
3770 | struct conexant_spec *spec = codec->spec; | ||
3771 | |||
3772 | if (!spec->auto_mic) | ||
3773 | return; | ||
3774 | if (!select_automic(codec, spec->auto_mic_ext, true)) | ||
3775 | if (!select_automic(codec, spec->auto_mic_dock, true)) | ||
3776 | select_automic(codec, spec->auto_mic_int, false); | ||
3777 | } | ||
3778 | |||
3779 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3780 | { | ||
3781 | int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; | ||
3782 | switch (res >> 26) { | ||
3783 | case CONEXANT_HP_EVENT: | ||
3784 | cx_auto_hp_automute(codec); | ||
3785 | break; | ||
3786 | case CONEXANT_LINE_EVENT: | ||
3787 | cx_auto_line_automute(codec); | ||
3788 | break; | ||
3789 | case CONEXANT_MIC_EVENT: | ||
3790 | cx_auto_automic(codec); | ||
3791 | snd_hda_input_jack_report(codec, nid); | ||
3792 | break; | ||
3793 | } | ||
3794 | } | ||
3795 | |||
3796 | /* check whether the pin config is suitable for auto-mic switching; | ||
3797 | * auto-mic is enabled only when one int-mic and one ext- and/or | ||
3798 | * one dock-mic exist | ||
3799 | */ | ||
3800 | static void cx_auto_check_auto_mic(struct hda_codec *codec) | ||
3801 | { | ||
3802 | struct conexant_spec *spec = codec->spec; | ||
3803 | int pset[INPUT_PIN_ATTR_NORMAL + 1]; | ||
3804 | int i; | ||
3805 | |||
3806 | for (i = 0; i < ARRAY_SIZE(pset); i++) | ||
3807 | pset[i] = -1; | ||
3808 | for (i = 0; i < spec->private_imux.num_items; i++) { | ||
3809 | hda_nid_t pin = spec->imux_info[i].pin; | ||
3810 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3811 | int type, attr; | ||
3812 | attr = snd_hda_get_input_pin_attr(def_conf); | ||
3813 | if (attr == INPUT_PIN_ATTR_UNUSED) | ||
3814 | return; /* invalid entry */ | ||
3815 | if (attr > INPUT_PIN_ATTR_NORMAL) | ||
3816 | attr = INPUT_PIN_ATTR_NORMAL; | ||
3817 | if (attr != INPUT_PIN_ATTR_INT && | ||
3818 | !is_jack_detectable(codec, pin)) | ||
3819 | return; /* non-detectable pin */ | ||
3820 | type = get_defcfg_device(def_conf); | ||
3821 | if (type != AC_JACK_MIC_IN && | ||
3822 | (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN)) | ||
3823 | return; /* no valid input type */ | ||
3824 | if (pset[attr] >= 0) | ||
3825 | return; /* already occupied */ | ||
3826 | pset[attr] = i; | ||
3827 | } | ||
3828 | if (pset[INPUT_PIN_ATTR_INT] < 0 || | ||
3829 | (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) | ||
3830 | return; /* no input to switch*/ | ||
3831 | spec->auto_mic = 1; | ||
3832 | spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; | ||
3833 | spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; | ||
3834 | spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; | ||
3835 | } | ||
3836 | |||
3837 | static void cx_auto_parse_input(struct hda_codec *codec) | ||
3838 | { | ||
3839 | struct conexant_spec *spec = codec->spec; | ||
3840 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3841 | struct hda_input_mux *imux; | ||
3842 | int i, j; | ||
3843 | |||
3844 | imux = &spec->private_imux; | ||
3845 | for (i = 0; i < cfg->num_inputs; i++) { | ||
3846 | for (j = 0; j < spec->num_adc_nids; j++) { | ||
3847 | hda_nid_t adc = spec->adc_nids[j]; | ||
3848 | int idx = get_input_connection(codec, adc, | ||
3849 | cfg->inputs[i].pin); | ||
3850 | if (idx >= 0) { | ||
3851 | const char *label; | ||
3852 | label = hda_get_autocfg_input_label(codec, cfg, i); | ||
3853 | spec->imux_info[imux->num_items].index = i; | ||
3854 | spec->imux_info[imux->num_items].boost = 0; | ||
3855 | spec->imux_info[imux->num_items].adc = adc; | ||
3856 | spec->imux_info[imux->num_items].pin = | ||
3857 | cfg->inputs[i].pin; | ||
3858 | snd_hda_add_imux_item(imux, label, idx, NULL); | ||
3859 | break; | ||
3860 | } | ||
3861 | } | ||
3862 | } | ||
3863 | if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) | ||
3864 | cx_auto_check_auto_mic(codec); | ||
3865 | if (imux->num_items > 1 && !spec->auto_mic) { | ||
3866 | for (i = 1; i < imux->num_items; i++) { | ||
3867 | if (spec->imux_info[i].adc != spec->imux_info[0].adc) { | ||
3868 | spec->adc_switching = 1; | ||
3869 | break; | ||
3870 | } | ||
3871 | } | ||
3872 | } | ||
3873 | } | ||
3874 | |||
3875 | /* get digital-input audio widget corresponding to the given pin */ | ||
3876 | static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin) | ||
3877 | { | ||
3878 | hda_nid_t nid, end_nid; | ||
3879 | |||
3880 | end_nid = codec->start_nid + codec->num_nodes; | ||
3881 | for (nid = codec->start_nid; nid < end_nid; nid++) { | ||
3882 | unsigned int wcaps = get_wcaps(codec, nid); | ||
3883 | unsigned int type = get_wcaps_type(wcaps); | ||
3884 | if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) { | ||
3885 | if (get_connection_index(codec, nid, pin) >= 0) | ||
3886 | return nid; | ||
3887 | } | ||
3888 | } | ||
3889 | return 0; | ||
3890 | } | ||
3891 | |||
3892 | static void cx_auto_parse_digital(struct hda_codec *codec) | ||
3893 | { | ||
3894 | struct conexant_spec *spec = codec->spec; | ||
3895 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3896 | hda_nid_t nid; | ||
3897 | |||
3898 | if (cfg->dig_outs && | ||
3899 | snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1) | ||
3900 | spec->multiout.dig_out_nid = nid; | ||
3901 | if (cfg->dig_in_pin) | ||
3902 | spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin); | ||
3903 | } | ||
3904 | |||
3905 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
3906 | static void cx_auto_parse_beep(struct hda_codec *codec) | ||
3907 | { | ||
3908 | struct conexant_spec *spec = codec->spec; | ||
3909 | hda_nid_t nid, end_nid; | ||
3910 | |||
3911 | end_nid = codec->start_nid + codec->num_nodes; | ||
3912 | for (nid = codec->start_nid; nid < end_nid; nid++) | ||
3913 | if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { | ||
3914 | set_beep_amp(spec, nid, 0, HDA_OUTPUT); | ||
3915 | break; | ||
3916 | } | ||
3917 | } | ||
3918 | #else | ||
3919 | #define cx_auto_parse_beep(codec) | ||
3920 | #endif | ||
3921 | |||
3922 | static int cx_auto_parse_auto_config(struct hda_codec *codec) | ||
3923 | { | ||
3924 | struct conexant_spec *spec = codec->spec; | ||
3925 | int err; | ||
3926 | |||
3927 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
3928 | if (err < 0) | ||
3929 | return err; | ||
3930 | |||
3931 | cx_auto_parse_output(codec); | ||
3932 | cx_auto_parse_input(codec); | ||
3933 | cx_auto_parse_digital(codec); | ||
3934 | cx_auto_parse_beep(codec); | ||
3935 | return 0; | ||
3936 | } | ||
3937 | |||
3938 | static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, | ||
3939 | hda_nid_t *pins, bool on) | ||
3940 | { | ||
3941 | int i; | ||
3942 | for (i = 0; i < num_pins; i++) { | ||
3943 | if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) | ||
3944 | snd_hda_codec_write(codec, pins[i], 0, | ||
3945 | AC_VERB_SET_EAPD_BTLENABLE, | ||
3946 | on ? 0x02 : 0); | ||
3947 | } | ||
3948 | } | ||
3949 | |||
3950 | static void select_connection(struct hda_codec *codec, hda_nid_t pin, | ||
3951 | hda_nid_t src) | ||
3952 | { | ||
3953 | int idx = get_connection_index(codec, pin, src); | ||
3954 | if (idx >= 0) | ||
3955 | snd_hda_codec_write(codec, pin, 0, | ||
3956 | AC_VERB_SET_CONNECT_SEL, idx); | ||
3957 | } | ||
3958 | |||
3959 | static void mute_outputs(struct hda_codec *codec, int num_nids, | ||
3960 | const hda_nid_t *nids) | ||
3961 | { | ||
3962 | int i, val; | ||
3963 | |||
3964 | for (i = 0; i < num_nids; i++) { | ||
3965 | hda_nid_t nid = nids[i]; | ||
3966 | if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) | ||
3967 | continue; | ||
3968 | if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE) | ||
3969 | val = AMP_OUT_MUTE; | ||
3970 | else | ||
3971 | val = AMP_OUT_ZERO; | ||
3972 | snd_hda_codec_write(codec, nid, 0, | ||
3973 | AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
3974 | } | ||
3975 | } | ||
3976 | |||
3977 | static void enable_unsol_pins(struct hda_codec *codec, int num_pins, | ||
3978 | hda_nid_t *pins, unsigned int tag) | ||
3979 | { | ||
3980 | int i; | ||
3981 | for (i = 0; i < num_pins; i++) | ||
3982 | snd_hda_codec_write(codec, pins[i], 0, | ||
3983 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3984 | AC_USRSP_EN | tag); | ||
3985 | } | ||
3986 | |||
3987 | static void cx_auto_init_output(struct hda_codec *codec) | ||
3988 | { | ||
3989 | struct conexant_spec *spec = codec->spec; | ||
3990 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3991 | hda_nid_t nid; | ||
3992 | int i; | ||
3993 | |||
3994 | mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids); | ||
3995 | for (i = 0; i < cfg->hp_outs; i++) | ||
3996 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | ||
3997 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | ||
3998 | mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); | ||
3999 | mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); | ||
4000 | mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); | ||
4001 | for (i = 0; i < spec->dac_info_filled; i++) { | ||
4002 | nid = spec->dac_info[i].dac; | ||
4003 | if (!nid) | ||
4004 | nid = spec->multiout.dac_nids[0]; | ||
4005 | select_connection(codec, spec->dac_info[i].pin, nid); | ||
4006 | } | ||
4007 | if (spec->auto_mute) { | ||
4008 | enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, | ||
4009 | CONEXANT_HP_EVENT); | ||
4010 | spec->hp_present = detect_jacks(codec, cfg->hp_outs, | ||
4011 | cfg->hp_pins); | ||
4012 | if (spec->detect_line) { | ||
4013 | enable_unsol_pins(codec, cfg->line_outs, | ||
4014 | cfg->line_out_pins, | ||
4015 | CONEXANT_LINE_EVENT); | ||
4016 | spec->line_present = | ||
4017 | detect_jacks(codec, cfg->line_outs, | ||
4018 | cfg->line_out_pins); | ||
4019 | } | ||
4020 | } | ||
4021 | cx_auto_update_speakers(codec); | ||
4022 | } | ||
4023 | |||
4024 | static void cx_auto_init_input(struct hda_codec *codec) | ||
4025 | { | ||
4026 | struct conexant_spec *spec = codec->spec; | ||
4027 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
4028 | int i, val; | ||
4029 | |||
4030 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
4031 | hda_nid_t nid = spec->adc_nids[i]; | ||
4032 | if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) | ||
4033 | continue; | ||
4034 | if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) | ||
4035 | val = AMP_IN_MUTE(0); | ||
4036 | else | ||
4037 | val = AMP_IN_UNMUTE(0); | ||
4038 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
4039 | val); | ||
4040 | } | ||
4041 | |||
4042 | for (i = 0; i < cfg->num_inputs; i++) { | ||
4043 | unsigned int type; | ||
4044 | if (cfg->inputs[i].type == AUTO_PIN_MIC) | ||
4045 | type = PIN_VREF80; | ||
4046 | else | ||
4047 | type = PIN_IN; | ||
4048 | snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, | ||
4049 | AC_VERB_SET_PIN_WIDGET_CONTROL, type); | ||
4050 | } | ||
4051 | |||
4052 | if (spec->auto_mic) { | ||
4053 | if (spec->auto_mic_ext >= 0) { | ||
4054 | snd_hda_codec_write(codec, | ||
4055 | cfg->inputs[spec->auto_mic_ext].pin, 0, | ||
4056 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4057 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
4058 | } | ||
4059 | if (spec->auto_mic_dock >= 0) { | ||
4060 | snd_hda_codec_write(codec, | ||
4061 | cfg->inputs[spec->auto_mic_dock].pin, 0, | ||
4062 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
4063 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
4064 | } | ||
4065 | cx_auto_automic(codec); | ||
4066 | } else { | ||
4067 | select_input_connection(codec, spec->imux_info[0].adc, | ||
4068 | spec->imux_info[0].pin); | ||
4069 | } | ||
4070 | } | ||
4071 | |||
4072 | static void cx_auto_init_digital(struct hda_codec *codec) | ||
4073 | { | ||
4074 | struct conexant_spec *spec = codec->spec; | ||
4075 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
4076 | |||
4077 | if (spec->multiout.dig_out_nid) | ||
4078 | snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0, | ||
4079 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
4080 | if (spec->dig_in_nid) | ||
4081 | snd_hda_codec_write(codec, cfg->dig_in_pin, 0, | ||
4082 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | ||
4083 | } | ||
4084 | |||
4085 | static int cx_auto_init(struct hda_codec *codec) | ||
4086 | { | ||
4087 | /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/ | ||
4088 | cx_auto_init_output(codec); | ||
4089 | cx_auto_init_input(codec); | ||
4090 | cx_auto_init_digital(codec); | ||
4091 | return 0; | ||
4092 | } | ||
4093 | |||
4094 | static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, | ||
4095 | const char *dir, int cidx, | ||
4096 | hda_nid_t nid, int hda_dir, int amp_idx) | ||
4097 | { | ||
4098 | static char name[32]; | ||
4099 | static struct snd_kcontrol_new knew[] = { | ||
4100 | HDA_CODEC_VOLUME(name, 0, 0, 0), | ||
4101 | HDA_CODEC_MUTE(name, 0, 0, 0), | ||
4102 | }; | ||
4103 | static const char * const sfx[2] = { "Volume", "Switch" }; | ||
4104 | int i, err; | ||
4105 | |||
4106 | for (i = 0; i < 2; i++) { | ||
4107 | struct snd_kcontrol *kctl; | ||
4108 | knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx, | ||
4109 | hda_dir); | ||
4110 | knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; | ||
4111 | knew[i].index = cidx; | ||
4112 | snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); | ||
4113 | kctl = snd_ctl_new1(&knew[i], codec); | ||
4114 | if (!kctl) | ||
4115 | return -ENOMEM; | ||
4116 | err = snd_hda_ctl_add(codec, nid, kctl); | ||
4117 | if (err < 0) | ||
4118 | return err; | ||
4119 | if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) | ||
4120 | break; | ||
4121 | } | ||
4122 | return 0; | ||
4123 | } | ||
4124 | |||
4125 | #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ | ||
4126 | cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0) | ||
4127 | |||
4128 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ | ||
4129 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) | ||
4130 | |||
4131 | static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, | ||
4132 | hda_nid_t pin, const char *name, int idx) | ||
4133 | { | ||
4134 | unsigned int caps; | ||
4135 | caps = query_amp_caps(codec, dac, HDA_OUTPUT); | ||
4136 | if (caps & AC_AMPCAP_NUM_STEPS) | ||
4137 | return cx_auto_add_pb_volume(codec, dac, name, idx); | ||
4138 | caps = query_amp_caps(codec, pin, HDA_OUTPUT); | ||
4139 | if (caps & AC_AMPCAP_NUM_STEPS) | ||
4140 | return cx_auto_add_pb_volume(codec, pin, name, idx); | ||
4141 | return 0; | ||
4142 | } | ||
4143 | |||
4144 | static int cx_auto_build_output_controls(struct hda_codec *codec) | ||
4145 | { | ||
4146 | struct conexant_spec *spec = codec->spec; | ||
4147 | int i, err; | ||
4148 | int num_line = 0, num_hp = 0, num_spk = 0; | ||
4149 | static const char * const texts[3] = { "Front", "Surround", "CLFE" }; | ||
4150 | |||
4151 | if (spec->dac_info_filled == 1) | ||
4152 | return try_add_pb_volume(codec, spec->dac_info[0].dac, | ||
4153 | spec->dac_info[0].pin, | ||
4154 | "Master", 0); | ||
4155 | |||
4156 | for (i = 0; i < spec->dac_info_filled; i++) { | ||
4157 | const char *label; | ||
4158 | int idx, type; | ||
4159 | if (!spec->dac_info[i].dac) | ||
4160 | continue; | ||
4161 | type = spec->dac_info[i].type; | ||
4162 | if (type == AUTO_PIN_LINE_OUT) | ||
4163 | type = spec->autocfg.line_out_type; | ||
4164 | switch (type) { | ||
4165 | case AUTO_PIN_LINE_OUT: | ||
4166 | default: | ||
4167 | label = texts[num_line++]; | ||
4168 | idx = 0; | ||
4169 | break; | ||
4170 | case AUTO_PIN_HP_OUT: | ||
4171 | label = "Headphone"; | ||
4172 | idx = num_hp++; | ||
4173 | break; | ||
4174 | case AUTO_PIN_SPEAKER_OUT: | ||
4175 | label = "Speaker"; | ||
4176 | idx = num_spk++; | ||
4177 | break; | ||
4178 | } | ||
4179 | err = try_add_pb_volume(codec, spec->dac_info[i].dac, | ||
4180 | spec->dac_info[i].pin, | ||
4181 | label, idx); | ||
4182 | if (err < 0) | ||
4183 | return err; | ||
4184 | } | ||
4185 | |||
4186 | if (spec->auto_mute) { | ||
4187 | err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); | ||
4188 | if (err < 0) | ||
4189 | return err; | ||
4190 | } | ||
4191 | |||
4192 | return 0; | ||
4193 | } | ||
4194 | |||
4195 | static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, | ||
4196 | const char *label, const char *pfx, | ||
4197 | int cidx) | ||
4198 | { | ||
4199 | struct conexant_spec *spec = codec->spec; | ||
4200 | int i; | ||
4201 | |||
4202 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
4203 | hda_nid_t adc_nid = spec->adc_nids[i]; | ||
4204 | int idx = get_input_connection(codec, adc_nid, nid); | ||
4205 | if (idx < 0) | ||
4206 | continue; | ||
4207 | return cx_auto_add_volume_idx(codec, label, pfx, | ||
4208 | cidx, adc_nid, HDA_INPUT, idx); | ||
4209 | } | ||
4210 | return 0; | ||
4211 | } | ||
4212 | |||
4213 | static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, | ||
4214 | const char *label, int cidx) | ||
4215 | { | ||
4216 | struct conexant_spec *spec = codec->spec; | ||
4217 | hda_nid_t mux, nid; | ||
4218 | int i, con; | ||
4219 | |||
4220 | nid = spec->imux_info[idx].pin; | ||
4221 | if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) | ||
4222 | return cx_auto_add_volume(codec, label, " Boost", cidx, | ||
4223 | nid, HDA_INPUT); | ||
4224 | con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, | ||
4225 | &mux, false, 0); | ||
4226 | if (con < 0) | ||
4227 | return 0; | ||
4228 | for (i = 0; i < idx; i++) { | ||
4229 | if (spec->imux_info[i].boost == mux) | ||
4230 | return 0; /* already present */ | ||
4231 | } | ||
4232 | |||
4233 | if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) { | ||
4234 | spec->imux_info[idx].boost = mux; | ||
4235 | return cx_auto_add_volume(codec, label, " Boost", 0, | ||
4236 | mux, HDA_OUTPUT); | ||
4237 | } | ||
4238 | return 0; | ||
4239 | } | ||
4240 | |||
4241 | static int cx_auto_build_input_controls(struct hda_codec *codec) | ||
4242 | { | ||
4243 | struct conexant_spec *spec = codec->spec; | ||
4244 | struct hda_input_mux *imux = &spec->private_imux; | ||
4245 | const char *prev_label; | ||
4246 | int input_conn[HDA_MAX_NUM_INPUTS]; | ||
4247 | int i, err, cidx; | ||
4248 | int multi_connection; | ||
4249 | |||
4250 | multi_connection = 0; | ||
4251 | for (i = 0; i < imux->num_items; i++) { | ||
4252 | cidx = get_input_connection(codec, spec->imux_info[i].adc, | ||
4253 | spec->imux_info[i].pin); | ||
4254 | input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; | ||
4255 | if (i > 0 && input_conn[i] != input_conn[0]) | ||
4256 | multi_connection = 1; | ||
4257 | } | ||
4258 | |||
4259 | prev_label = NULL; | ||
4260 | cidx = 0; | ||
4261 | for (i = 0; i < imux->num_items; i++) { | ||
4262 | hda_nid_t nid = spec->imux_info[i].pin; | ||
4263 | const char *label; | ||
4264 | |||
4265 | label = hda_get_autocfg_input_label(codec, &spec->autocfg, | ||
4266 | spec->imux_info[i].index); | ||
4267 | if (label == prev_label) | ||
4268 | cidx++; | ||
4269 | else | ||
4270 | cidx = 0; | ||
4271 | prev_label = label; | ||
4272 | |||
4273 | err = cx_auto_add_boost_volume(codec, i, label, cidx); | ||
4274 | if (err < 0) | ||
4275 | return err; | ||
4276 | |||
4277 | if (!multi_connection) { | ||
4278 | if (i > 0) | ||
4279 | continue; | ||
4280 | err = cx_auto_add_capture_volume(codec, nid, | ||
4281 | "Capture", "", cidx); | ||
4282 | } else { | ||
4283 | err = cx_auto_add_capture_volume(codec, nid, | ||
4284 | label, " Capture", cidx); | ||
4285 | } | ||
4286 | if (err < 0) | ||
4287 | return err; | ||
4288 | } | ||
4289 | |||
4290 | if (spec->private_imux.num_items > 1 && !spec->auto_mic) { | ||
4291 | err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); | ||
4292 | if (err < 0) | ||
4293 | return err; | ||
4294 | } | ||
4295 | |||
4296 | return 0; | ||
4297 | } | ||
4298 | |||
4299 | static int cx_auto_build_controls(struct hda_codec *codec) | ||
4300 | { | ||
4301 | int err; | ||
4302 | |||
4303 | err = cx_auto_build_output_controls(codec); | ||
4304 | if (err < 0) | ||
4305 | return err; | ||
4306 | err = cx_auto_build_input_controls(codec); | ||
4307 | if (err < 0) | ||
4308 | return err; | ||
4309 | return conexant_build_controls(codec); | ||
4310 | } | ||
4311 | |||
4312 | static int cx_auto_search_adcs(struct hda_codec *codec) | ||
4313 | { | ||
4314 | struct conexant_spec *spec = codec->spec; | ||
4315 | hda_nid_t nid, end_nid; | ||
4316 | |||
4317 | end_nid = codec->start_nid + codec->num_nodes; | ||
4318 | for (nid = codec->start_nid; nid < end_nid; nid++) { | ||
4319 | unsigned int caps = get_wcaps(codec, nid); | ||
4320 | if (get_wcaps_type(caps) != AC_WID_AUD_IN) | ||
4321 | continue; | ||
4322 | if (caps & AC_WCAP_DIGITAL) | ||
4323 | continue; | ||
4324 | if (snd_BUG_ON(spec->num_adc_nids >= | ||
4325 | ARRAY_SIZE(spec->private_adc_nids))) | ||
4326 | break; | ||
4327 | spec->private_adc_nids[spec->num_adc_nids++] = nid; | ||
4328 | } | ||
4329 | spec->adc_nids = spec->private_adc_nids; | ||
4330 | return 0; | ||
4331 | } | ||
4332 | |||
4333 | |||
4334 | static const struct hda_codec_ops cx_auto_patch_ops = { | ||
4335 | .build_controls = cx_auto_build_controls, | ||
4336 | .build_pcms = conexant_build_pcms, | ||
4337 | .init = cx_auto_init, | ||
4338 | .free = conexant_free, | ||
4339 | .unsol_event = cx_auto_unsol_event, | ||
4340 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
4341 | .suspend = conexant_suspend, | ||
4342 | #endif | ||
4343 | .reboot_notify = snd_hda_shutup_pins, | ||
4344 | }; | ||
4345 | |||
4346 | static int patch_conexant_auto(struct hda_codec *codec) | ||
4347 | { | ||
4348 | struct conexant_spec *spec; | ||
4349 | int err; | ||
4350 | |||
4351 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
4352 | codec->chip_name); | ||
4353 | |||
4354 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
4355 | if (!spec) | ||
4356 | return -ENOMEM; | ||
4357 | codec->spec = spec; | ||
4358 | codec->pin_amp_workaround = 1; | ||
4359 | err = cx_auto_search_adcs(codec); | ||
4360 | if (err < 0) | ||
4361 | return err; | ||
4362 | err = cx_auto_parse_auto_config(codec); | ||
4363 | if (err < 0) { | ||
4364 | kfree(codec->spec); | ||
4365 | codec->spec = NULL; | ||
4366 | return err; | ||
4367 | } | ||
4368 | spec->capture_stream = &cx_auto_pcm_analog_capture; | ||
4369 | codec->patch_ops = cx_auto_patch_ops; | ||
4370 | if (spec->beep_amp) | ||
4371 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
4372 | return 0; | ||
4373 | } | ||
4374 | |||
4375 | /* | ||
3257 | */ | 4376 | */ |
3258 | 4377 | ||
3259 | static struct hda_codec_preset snd_hda_preset_conexant[] = { | 4378 | static const struct hda_codec_preset snd_hda_preset_conexant[] = { |
3260 | { .id = 0x14f15045, .name = "CX20549 (Venice)", | 4379 | { .id = 0x14f15045, .name = "CX20549 (Venice)", |
3261 | .patch = patch_cxt5045 }, | 4380 | .patch = patch_cxt5045 }, |
3262 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", | 4381 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", |
@@ -3271,6 +4390,26 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
3271 | .patch = patch_cxt5066 }, | 4390 | .patch = patch_cxt5066 }, |
3272 | { .id = 0x14f15069, .name = "CX20585", | 4391 | { .id = 0x14f15069, .name = "CX20585", |
3273 | .patch = patch_cxt5066 }, | 4392 | .patch = patch_cxt5066 }, |
4393 | { .id = 0x14f1506c, .name = "CX20588", | ||
4394 | .patch = patch_cxt5066 }, | ||
4395 | { .id = 0x14f1506e, .name = "CX20590", | ||
4396 | .patch = patch_cxt5066 }, | ||
4397 | { .id = 0x14f15097, .name = "CX20631", | ||
4398 | .patch = patch_conexant_auto }, | ||
4399 | { .id = 0x14f15098, .name = "CX20632", | ||
4400 | .patch = patch_conexant_auto }, | ||
4401 | { .id = 0x14f150a1, .name = "CX20641", | ||
4402 | .patch = patch_conexant_auto }, | ||
4403 | { .id = 0x14f150a2, .name = "CX20642", | ||
4404 | .patch = patch_conexant_auto }, | ||
4405 | { .id = 0x14f150ab, .name = "CX20651", | ||
4406 | .patch = patch_conexant_auto }, | ||
4407 | { .id = 0x14f150ac, .name = "CX20652", | ||
4408 | .patch = patch_conexant_auto }, | ||
4409 | { .id = 0x14f150b8, .name = "CX20664", | ||
4410 | .patch = patch_conexant_auto }, | ||
4411 | { .id = 0x14f150b9, .name = "CX20665", | ||
4412 | .patch = patch_conexant_auto }, | ||
3274 | {} /* terminator */ | 4413 | {} /* terminator */ |
3275 | }; | 4414 | }; |
3276 | 4415 | ||
@@ -3281,6 +4420,16 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066"); | |||
3281 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); | 4420 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); |
3282 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); | 4421 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); |
3283 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); | 4422 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); |
4423 | MODULE_ALIAS("snd-hda-codec-id:14f1506c"); | ||
4424 | MODULE_ALIAS("snd-hda-codec-id:14f1506e"); | ||
4425 | MODULE_ALIAS("snd-hda-codec-id:14f15097"); | ||
4426 | MODULE_ALIAS("snd-hda-codec-id:14f15098"); | ||
4427 | MODULE_ALIAS("snd-hda-codec-id:14f150a1"); | ||
4428 | MODULE_ALIAS("snd-hda-codec-id:14f150a2"); | ||
4429 | MODULE_ALIAS("snd-hda-codec-id:14f150ab"); | ||
4430 | MODULE_ALIAS("snd-hda-codec-id:14f150ac"); | ||
4431 | MODULE_ALIAS("snd-hda-codec-id:14f150b8"); | ||
4432 | MODULE_ALIAS("snd-hda-codec-id:14f150b9"); | ||
3284 | 4433 | ||
3285 | MODULE_LICENSE("GPL"); | 4434 | MODULE_LICENSE("GPL"); |
3286 | MODULE_DESCRIPTION("Conexant HD-audio codec"); | 4435 | MODULE_DESCRIPTION("Conexant HD-audio codec"); |