diff options
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 233 |
1 files changed, 230 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a44d64e828d5..e64e29dac824 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include "hda_codec.h" | 30 | #include "hda_codec.h" |
31 | #include "hda_local.h" | 31 | #include "hda_local.h" |
32 | #define NUM_PINS 11 | ||
32 | 33 | ||
33 | 34 | ||
34 | /* board config type */ | 35 | /* board config type */ |
@@ -38,6 +39,7 @@ enum { | |||
38 | CMI_FULL, /* back 6-jack + front-panel 2-jack */ | 39 | CMI_FULL, /* back 6-jack + front-panel 2-jack */ |
39 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ | 40 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ |
40 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ | 41 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ |
42 | CMI_AUTO, /* let driver guess it */ | ||
41 | }; | 43 | }; |
42 | 44 | ||
43 | struct cmi_spec { | 45 | struct cmi_spec { |
@@ -48,6 +50,7 @@ struct cmi_spec { | |||
48 | 50 | ||
49 | /* playback */ | 51 | /* playback */ |
50 | struct hda_multi_out multiout; | 52 | struct hda_multi_out multiout; |
53 | hda_nid_t dac_nids[4]; /* NID for each DAC */ | ||
51 | 54 | ||
52 | /* capture */ | 55 | /* capture */ |
53 | hda_nid_t *adc_nids; | 56 | hda_nid_t *adc_nids; |
@@ -63,6 +66,15 @@ struct cmi_spec { | |||
63 | const struct cmi_channel_mode *channel_modes; | 66 | const struct cmi_channel_mode *channel_modes; |
64 | 67 | ||
65 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 68 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
69 | |||
70 | /* pin deafault configuration */ | ||
71 | hda_nid_t pin_nid[NUM_PINS]; | ||
72 | unsigned int def_conf[NUM_PINS]; | ||
73 | unsigned int pin_def_confs; | ||
74 | |||
75 | /* multichannel pins */ | ||
76 | hda_nid_t multich_pin[4]; /* max 8-channel */ | ||
77 | struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ | ||
66 | }; | 78 | }; |
67 | 79 | ||
68 | /* | 80 | /* |
@@ -353,6 +365,175 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
353 | return 0; | 365 | return 0; |
354 | } | 366 | } |
355 | 367 | ||
368 | #define AC_DEFCFG_ASSOC_SHIFT 4 | ||
369 | #define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) | ||
370 | #define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) | ||
371 | #define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) | ||
372 | |||
373 | /* get all pin default configuration in def_conf */ | ||
374 | static int cmi9880_get_pin_def_config(struct hda_codec *codec) | ||
375 | { | ||
376 | struct cmi_spec *spec = codec->spec; | ||
377 | hda_nid_t nid, nid_start; | ||
378 | int i = 0, nodes; | ||
379 | |||
380 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); | ||
381 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | ||
382 | unsigned int wid_caps = snd_hda_param_read(codec, nid, | ||
383 | AC_PAR_AUDIO_WIDGET_CAP); | ||
384 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
385 | /* read all default configuration for pin complex */ | ||
386 | if (wid_type == AC_WID_PIN) { | ||
387 | spec->pin_nid[i] = nid; | ||
388 | spec->def_conf[i] = | ||
389 | snd_hda_codec_read(codec, nid, 0, | ||
390 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
391 | i++; | ||
392 | } | ||
393 | } | ||
394 | spec->pin_def_confs = i; | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | /* get a pin default configuration of nid in def_conf */ | ||
399 | static unsigned int cmi9880_get_def_config(struct hda_codec *codec, hda_nid_t nid) | ||
400 | { | ||
401 | struct cmi_spec *spec = codec->spec; | ||
402 | int i = 0; | ||
403 | |||
404 | while (spec->pin_nid[i] != nid && i < spec->pin_def_confs) | ||
405 | i++; | ||
406 | if (i == spec->pin_def_confs) | ||
407 | return (unsigned int) -1; | ||
408 | else | ||
409 | return spec->def_conf[i]; | ||
410 | } | ||
411 | |||
412 | /* decide what pins to use for multichannel playback */ | ||
413 | static int cmi9880_get_multich_pins(struct hda_codec *codec) | ||
414 | { | ||
415 | struct cmi_spec *spec = codec->spec; | ||
416 | int i, j, pins, seq[4]; | ||
417 | int max_channel = 0; | ||
418 | unsigned int def_conf, sequence; | ||
419 | hda_nid_t nid; | ||
420 | |||
421 | memset(spec->multich_pin, 0, sizeof(spec->multich_pin)); | ||
422 | for (pins = 0, i = 0; i < spec->pin_def_confs && pins < 4; i++) { | ||
423 | def_conf = spec->def_conf[i]; | ||
424 | /* skip pin not connected */ | ||
425 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | ||
426 | continue; | ||
427 | /* get the sequence if association == 1 */ | ||
428 | /* the other pins have association = 0, incorrect in spec 1.0 */ | ||
429 | if (get_defcfg_association(def_conf) == 1) { | ||
430 | sequence = get_defcfg_sequence(def_conf); | ||
431 | seq[pins] = sequence; | ||
432 | spec->multich_pin[pins] = spec->pin_nid[i]; | ||
433 | pins++; // ready for next slot | ||
434 | max_channel += 2; | ||
435 | } | ||
436 | } | ||
437 | /* sort by sequence, data collected here will be for Windows */ | ||
438 | for (i = 0; i < pins; i++) { | ||
439 | for (j = i + 1; j < pins; j++) { | ||
440 | if (seq[j] < seq[i]) { | ||
441 | sequence = seq[j]; | ||
442 | nid = spec->multich_pin[j]; | ||
443 | seq[j] = seq[i]; | ||
444 | spec->multich_pin[j] = spec->multich_pin[i]; | ||
445 | seq[i] = sequence; | ||
446 | spec->multich_pin[i] = nid; | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | /* the pin assignment is for front, C/LFE, surround and back */ | ||
451 | if (max_channel >= 6) { | ||
452 | hda_nid_t temp; | ||
453 | /* exchange pin of C/LFE and surround */ | ||
454 | temp = spec->multich_pin[1]; | ||
455 | spec->multich_pin[1] = spec->multich_pin[2]; | ||
456 | spec->multich_pin[2] = temp; | ||
457 | } | ||
458 | return max_channel; | ||
459 | } | ||
460 | |||
461 | /* fill in the multi_dac_nids table, which will decide | ||
462 | which audio widget to use for each channel */ | ||
463 | static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec) | ||
464 | { | ||
465 | struct cmi_spec *spec = codec->spec; | ||
466 | hda_nid_t nid; | ||
467 | int assigned[4]; | ||
468 | int i, j; | ||
469 | |||
470 | /* clear the table, only one c-media dac assumed here */ | ||
471 | memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); | ||
472 | memset(assigned, 0, sizeof(assigned)); | ||
473 | /* check the pins we found */ | ||
474 | for (i = 0; i < spec->multiout.max_channels / 2; i++) { | ||
475 | nid = spec->multich_pin[i]; | ||
476 | /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ | ||
477 | if (nid <= 0x0e && nid >= 0x0b) { | ||
478 | spec->dac_nids[i] = nid - 0x08; | ||
479 | assigned[nid - 0x0b] = 1; | ||
480 | } | ||
481 | } | ||
482 | /* left pin can be connect to any audio widget */ | ||
483 | for (i = 0; i < spec->multiout.max_channels / 2; i++) { | ||
484 | if (!assigned[i]) { | ||
485 | /* search for an empty channel */ | ||
486 | /* I should also check the pin type */ | ||
487 | for (j = 0; j < ARRAY_SIZE(spec->dac_nids); j++) | ||
488 | if (! spec->dac_nids[j]) { | ||
489 | spec->dac_nids[j] = i + 3; | ||
490 | assigned[i] = 1; | ||
491 | break; | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | /* create multi_init table, which is used for multichannel initialization */ | ||
499 | static int cmi9880_fill_multi_init(struct hda_codec *codec) | ||
500 | { | ||
501 | struct cmi_spec *spec = codec->spec; | ||
502 | hda_nid_t nid; | ||
503 | int i, j, k, len; | ||
504 | |||
505 | /* clear the table, only one c-media dac assumed here */ | ||
506 | memset(spec->multi_init, 0, sizeof(spec->multi_init)); | ||
507 | for (j = 0, i = 0; i < spec->multiout.max_channels / 2; i++) { | ||
508 | hda_nid_t conn[4]; | ||
509 | nid = spec->multich_pin[i]; | ||
510 | /* set as output */ | ||
511 | spec->multi_init[j].nid = nid; | ||
512 | spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; | ||
513 | spec->multi_init[j].param = 0xc0; | ||
514 | j++; | ||
515 | /* nid 0x0f,0x10,0x1f,0x20 are needed to set connection */ | ||
516 | switch (nid) { | ||
517 | case 0x0f: | ||
518 | case 0x10: | ||
519 | case 0x1f: | ||
520 | case 0x20: | ||
521 | /* set connection */ | ||
522 | spec->multi_init[j].nid = nid; | ||
523 | spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; | ||
524 | /* find the index in connect list */ | ||
525 | len = snd_hda_get_connections(codec, nid, conn, 4); | ||
526 | for (k = 0; k < len; k++) | ||
527 | if (conn[k] == spec->dac_nids[i]) | ||
528 | break; | ||
529 | spec->multi_init[j].param = k < len ? k : 0; | ||
530 | j++; | ||
531 | break; | ||
532 | } | ||
533 | } | ||
534 | return 0; | ||
535 | } | ||
536 | |||
356 | static int cmi9880_init(struct hda_codec *codec) | 537 | static int cmi9880_init(struct hda_codec *codec) |
357 | { | 538 | { |
358 | struct cmi_spec *spec = codec->spec; | 539 | struct cmi_spec *spec = codec->spec; |
@@ -360,6 +541,8 @@ static int cmi9880_init(struct hda_codec *codec) | |||
360 | snd_hda_sequence_write(codec, cmi9880_allout_init); | 541 | snd_hda_sequence_write(codec, cmi9880_allout_init); |
361 | else | 542 | else |
362 | snd_hda_sequence_write(codec, cmi9880_basic_init); | 543 | snd_hda_sequence_write(codec, cmi9880_basic_init); |
544 | if (spec->board_config == CMI_AUTO) | ||
545 | snd_hda_sequence_write(codec, spec->multi_init); | ||
363 | return 0; | 546 | return 0; |
364 | } | 547 | } |
365 | 548 | ||
@@ -546,6 +729,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = { | |||
546 | { .modelname = "full", .config = CMI_FULL }, | 729 | { .modelname = "full", .config = CMI_FULL }, |
547 | { .modelname = "full_dig", .config = CMI_FULL_DIG }, | 730 | { .modelname = "full_dig", .config = CMI_FULL_DIG }, |
548 | { .modelname = "allout", .config = CMI_ALLOUT }, | 731 | { .modelname = "allout", .config = CMI_ALLOUT }, |
732 | { .modelname = "auto", .config = CMI_AUTO }, | ||
549 | {} /* terminator */ | 733 | {} /* terminator */ |
550 | }; | 734 | }; |
551 | 735 | ||
@@ -570,10 +754,13 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
570 | codec->spec = spec; | 754 | codec->spec = spec; |
571 | spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); | 755 | spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); |
572 | if (spec->board_config < 0) { | 756 | if (spec->board_config < 0) { |
573 | snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); | 757 | snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); |
574 | spec->board_config = CMI_FULL_DIG; /* try everything */ | 758 | spec->board_config = CMI_AUTO; /* try everything */ |
575 | } | 759 | } |
576 | 760 | ||
761 | /* copy default DAC NIDs */ | ||
762 | memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); | ||
763 | |||
577 | switch (spec->board_config) { | 764 | switch (spec->board_config) { |
578 | case CMI_MINIMAL: | 765 | case CMI_MINIMAL: |
579 | case CMI_MIN_FP: | 766 | case CMI_MIN_FP: |
@@ -605,10 +792,50 @@ static int patch_cmi9880(struct hda_codec *codec) | |||
605 | spec->input_mux = &cmi9880_no_line_mux; | 792 | spec->input_mux = &cmi9880_no_line_mux; |
606 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | 793 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; |
607 | break; | 794 | break; |
795 | case CMI_AUTO: | ||
796 | { | ||
797 | unsigned int port_e, port_f, port_g, port_h; | ||
798 | unsigned int port_spdifi, port_spdifo; | ||
799 | /* collect pin default configuration */ | ||
800 | cmi9880_get_pin_def_config(codec); | ||
801 | port_e = cmi9880_get_def_config(codec, 0x0f); | ||
802 | port_f = cmi9880_get_def_config(codec, 0x10); | ||
803 | port_g = cmi9880_get_def_config(codec, 0x1f); | ||
804 | port_h = cmi9880_get_def_config(codec, 0x20); | ||
805 | port_spdifi = cmi9880_get_def_config(codec, 0x13); | ||
806 | port_spdifo = cmi9880_get_def_config(codec, 0x12); | ||
807 | spec->front_panel = 1; | ||
808 | if ((get_defcfg_connect(port_e) == AC_JACK_PORT_NONE) | ||
809 | || (get_defcfg_connect(port_f) == AC_JACK_PORT_NONE)) { | ||
810 | spec->surr_switch = 1; | ||
811 | /* no front panel */ | ||
812 | if ((get_defcfg_connect(port_g) == AC_JACK_PORT_NONE) | ||
813 | || (get_defcfg_connect(port_h) == AC_JACK_PORT_NONE)) { | ||
814 | /* no optional rear panel */ | ||
815 | spec->board_config = CMI_MINIMAL; | ||
816 | spec->front_panel = 0; | ||
817 | spec->num_ch_modes = 2; | ||
818 | } else | ||
819 | spec->board_config = CMI_MIN_FP; | ||
820 | spec->num_ch_modes = 3; | ||
821 | spec->channel_modes = cmi9880_channel_modes; | ||
822 | spec->input_mux = &cmi9880_basic_mux; | ||
823 | } else { | ||
824 | spec->input_mux = &cmi9880_basic_mux; | ||
825 | if (get_defcfg_connect(port_spdifo) != 1) | ||
826 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | ||
827 | if (get_defcfg_connect(port_spdifi) != 1) | ||
828 | spec->dig_in_nid = CMI_DIG_IN_NID; | ||
829 | } | ||
830 | spec->multiout.max_channels = cmi9880_get_multich_pins(codec); | ||
831 | cmi9880_fill_multi_dac_nids(codec); | ||
832 | cmi9880_fill_multi_init(codec); | ||
833 | } | ||
834 | break; | ||
608 | } | 835 | } |
609 | 836 | ||
610 | spec->multiout.num_dacs = 4; | 837 | spec->multiout.num_dacs = 4; |
611 | spec->multiout.dac_nids = cmi9880_dac_nids; | 838 | spec->multiout.dac_nids = spec->dac_nids; |
612 | 839 | ||
613 | spec->adc_nids = cmi9880_adc_nids; | 840 | spec->adc_nids = cmi9880_adc_nids; |
614 | 841 | ||