aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-06-21 09:57:44 -0400
committerTakashi Iwai <tiwai@suse.de>2011-06-21 10:02:32 -0400
commit09a9ad69a5467fbda3fd358d2be155c22aa416e4 (patch)
tree336c02b4a218897b40413a92cc09c26ac2599de7 /sound/pci
parenta934d5a983528543850c90b29bedbdfd71f7097b (diff)
ALSA: hda - VT1708 independent HP routing fix
The codecs like VT1708 needs more complicated routing using the mixer widget rather than the simple selector widgets. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/patch_via.c222
1 files changed, 122 insertions, 100 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 5b907b356951..bceb6b2364fe 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -83,10 +83,20 @@ enum VIA_HDA_CODEC {
83 83
84#define MAX_NID_PATH_DEPTH 5 84#define MAX_NID_PATH_DEPTH 5
85 85
86/* output-path: DAC -> ... -> pin
87 * idx[] contains the source index number of the next widget;
88 * e.g. idx[0] is the index of the DAC selected by path[1] widget
89 * multi[] indicates whether it's a selector widget with multi-connectors
90 * (i.e. the connection selection is mandatory)
91 * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
92 */
86struct nid_path { 93struct nid_path {
87 int depth; 94 int depth;
88 hda_nid_t path[MAX_NID_PATH_DEPTH]; 95 hda_nid_t path[MAX_NID_PATH_DEPTH];
89 short idx[MAX_NID_PATH_DEPTH]; 96 unsigned char idx[MAX_NID_PATH_DEPTH];
97 unsigned char multi[MAX_NID_PATH_DEPTH];
98 unsigned int vol_ctl;
99 unsigned int mute_ctl;
90}; 100};
91 101
92struct via_spec { 102struct via_spec {
@@ -422,43 +432,39 @@ static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
422 return false; 432 return false;
423} 433}
424 434
425#define have_vol_or_mute(codec, nid, dir) \ 435#define have_mute(codec, nid, dir) \
426 check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE) 436 check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
427 437
428/* unmute input amp and select the specificed source */ 438/* enable/disable the output-route */
429static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid, 439static void activate_output_path(struct hda_codec *codec, struct nid_path *path,
430 hda_nid_t src, hda_nid_t mix) 440 bool enable, bool force)
431{ 441{
432 int idx, num_conns; 442 int i;
433 443 for (i = 0; i < path->depth; i++) {
434 idx = __get_connection_index(codec, nid, src, &num_conns); 444 hda_nid_t src, dst;
435 if (idx < 0) 445 int idx = path->idx[i];
436 return; 446 src = path->path[i];
437 447 if (i < path->depth - 1)
438 /* select the route explicitly when multiple connections exist */ 448 dst = path->path[i + 1];
439 if (num_conns > 1 && 449 else
440 get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX) 450 dst = 0;
441 snd_hda_codec_write(codec, nid, 0, 451 if (enable && path->multi[i])
442 AC_VERB_SET_CONNECT_SEL, idx); 452 snd_hda_codec_write(codec, dst, 0,
443 453 AC_VERB_SET_CONNECT_SEL, idx);
444 /* unmute if the input amp is present */ 454 if (have_mute(codec, dst, HDA_INPUT)) {
445 if (have_vol_or_mute(codec, nid, HDA_INPUT)) 455 int val = enable ? AMP_IN_UNMUTE(idx) :
446 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 456 AMP_IN_MUTE(idx);
447 AMP_IN_UNMUTE(idx)); 457 snd_hda_codec_write(codec, dst, 0,
448 458 AC_VERB_SET_AMP_GAIN_MUTE, val);
449 /* unmute the src output */ 459 }
450 if (have_vol_or_mute(codec, src, HDA_OUTPUT)) 460 if (!force && (src == path->vol_ctl || src == path->mute_ctl))
451 snd_hda_codec_write(codec, src, 0, AC_VERB_SET_AMP_GAIN_MUTE, 461 continue;
452 AMP_OUT_UNMUTE); 462 if (have_mute(codec, src, HDA_OUTPUT)) {
453 463 int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE;
454 /* unmute AA-path if present */ 464 snd_hda_codec_write(codec, src, 0,
455 if (!mix || mix == src) 465 AC_VERB_SET_AMP_GAIN_MUTE, val);
456 return; 466 }
457 idx = __get_connection_index(codec, nid, mix, NULL); 467 }
458 if (idx >= 0 && have_vol_or_mute(codec, nid, HDA_INPUT))
459 snd_hda_codec_write(codec, nid, 0,
460 AC_VERB_SET_AMP_GAIN_MUTE,
461 AMP_IN_UNMUTE(idx));
462} 468}
463 469
464/* set the given pin as output */ 470/* set the given pin as output */
@@ -474,16 +480,18 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
474 AC_VERB_SET_EAPD_BTLENABLE, 0x02); 480 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
475} 481}
476 482
477static void via_auto_init_output(struct hda_codec *codec, hda_nid_t pin, 483static void via_auto_init_output(struct hda_codec *codec,
478 int pin_type, struct nid_path *path) 484 struct nid_path *path, int pin_type,
485 bool force)
479{ 486{
480 struct via_spec *spec = codec->spec; 487 struct via_spec *spec = codec->spec;
481 unsigned int caps; 488 unsigned int caps;
482 hda_nid_t nid; 489 hda_nid_t pin, nid;
483 int i; 490 int i, idx;
484 491
485 if (!pin) 492 if (!path->depth)
486 return; 493 return;
494 pin = path->path[path->depth - 1];
487 495
488 init_output_pin(codec, pin, pin_type); 496 init_output_pin(codec, pin, pin_type);
489 caps = query_amp_caps(codec, pin, HDA_OUTPUT); 497 caps = query_amp_caps(codec, pin, HDA_OUTPUT);
@@ -494,34 +502,48 @@ static void via_auto_init_output(struct hda_codec *codec, hda_nid_t pin,
494 AMP_OUT_MUTE | val); 502 AMP_OUT_MUTE | val);
495 } 503 }
496 504
497 /* initialize the output path */ 505 activate_output_path(codec, path, true, force);
506
507 /* initialize the AA-path */
508 if (!spec->aa_mix_nid)
509 return;
498 for (i = path->depth - 1; i > 0; i--) { 510 for (i = path->depth - 1; i > 0; i--) {
499 nid = path->path[i - 1]; 511 nid = path->path[i];
500 unmute_and_select(codec, path->path[i], nid, spec->aa_mix_nid); 512 idx = get_connection_index(codec, nid, spec->aa_mix_nid);
513 if (idx >= 0) {
514 if (have_mute(codec, nid, HDA_INPUT))
515 snd_hda_codec_write(codec, nid, 0,
516 AC_VERB_SET_AMP_GAIN_MUTE,
517 AMP_IN_UNMUTE(idx));
518 break;
519 }
501 } 520 }
502} 521}
503 522
504
505static void via_auto_init_multi_out(struct hda_codec *codec) 523static void via_auto_init_multi_out(struct hda_codec *codec)
506{ 524{
507 struct via_spec *spec = codec->spec; 525 struct via_spec *spec = codec->spec;
508 int i; 526 int i;
509 527
510 for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) 528 for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++)
511 via_auto_init_output(codec, spec->autocfg.line_out_pins[i], 529 via_auto_init_output(codec, &spec->out_path[i], PIN_OUT, true);
512 PIN_OUT, &spec->out_path[i]);
513} 530}
514 531
515static void via_auto_init_hp_out(struct hda_codec *codec) 532static void via_auto_init_hp_out(struct hda_codec *codec)
516{ 533{
517 struct via_spec *spec = codec->spec; 534 struct via_spec *spec = codec->spec;
518 535
519 if (spec->hp_dac_nid) 536 if (!spec->hp_dac_nid) {
520 via_auto_init_output(codec, spec->autocfg.hp_pins[0], PIN_HP, 537 via_auto_init_output(codec, &spec->hp_dep_path, PIN_HP, true);
521 &spec->hp_path); 538 return;
522 else 539 }
523 via_auto_init_output(codec, spec->autocfg.hp_pins[0], PIN_HP, 540 if (spec->hp_independent_mode) {
524 &spec->hp_dep_path); 541 activate_output_path(codec, &spec->hp_dep_path, false, false);
542 via_auto_init_output(codec, &spec->hp_path, PIN_HP, true);
543 } else {
544 activate_output_path(codec, &spec->hp_path, false, false);
545 via_auto_init_output(codec, &spec->hp_dep_path, PIN_HP, true);
546 }
525} 547}
526 548
527static void via_auto_init_speaker_out(struct hda_codec *codec) 549static void via_auto_init_speaker_out(struct hda_codec *codec)
@@ -529,8 +551,7 @@ static void via_auto_init_speaker_out(struct hda_codec *codec)
529 struct via_spec *spec = codec->spec; 551 struct via_spec *spec = codec->spec;
530 552
531 if (spec->autocfg.speaker_outs) 553 if (spec->autocfg.speaker_outs)
532 via_auto_init_output(codec, spec->autocfg.speaker_pins[0], 554 via_auto_init_output(codec, &spec->speaker_path, PIN_OUT, true);
533 PIN_OUT, &spec->speaker_path);
534} 555}
535 556
536static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); 557static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin);
@@ -738,27 +759,14 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
738{ 759{
739 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 760 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
740 struct via_spec *spec = codec->spec; 761 struct via_spec *spec = codec->spec;
741 hda_nid_t nid, src;
742 int i, idx, num_conns;
743 struct nid_path *path;
744 762
745 spec->hp_independent_mode = !!ucontrol->value.enumerated.item[0]; 763 spec->hp_independent_mode = !!ucontrol->value.enumerated.item[0];
746 if (spec->hp_independent_mode) 764 if (spec->hp_independent_mode) {
747 path = &spec->hp_path; 765 activate_output_path(codec, &spec->hp_dep_path, false, false);
748 else 766 activate_output_path(codec, &spec->hp_path, true, false);
749 path = &spec->hp_dep_path; 767 } else {
750 768 activate_output_path(codec, &spec->hp_path, false, false);
751 /* re-route the output path */ 769 activate_output_path(codec, &spec->hp_dep_path, true, false);
752 for (i = path->depth - 1; i > 0; i--) {
753 nid = path->path[i];
754 src = path->path[i - 1];
755 idx = __get_connection_index(codec, nid, src, &num_conns);
756 if (idx < 0)
757 continue;
758 if (num_conns > 1 &&
759 get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
760 snd_hda_codec_write(codec, nid, 0,
761 AC_VERB_SET_CONNECT_SEL, idx);
762 } 770 }
763 771
764 /* update jack power state */ 772 /* update jack power state */
@@ -1577,12 +1585,8 @@ static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid,
1577 for (i = 0; i < nums; i++) { 1585 for (i = 0; i < nums; i++) {
1578 if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) 1586 if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT)
1579 continue; 1587 continue;
1580 if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) { 1588 if (conn[i] == target_dac || is_empty_dac(codec, conn[i]))
1581 path->path[0] = conn[i]; 1589 goto found;
1582 path->idx[0] = i;
1583 path->depth = 1;
1584 return true;
1585 }
1586 } 1590 }
1587 if (depth >= MAX_NID_PATH_DEPTH) 1591 if (depth >= MAX_NID_PATH_DEPTH)
1588 return false; 1592 return false;
@@ -1593,14 +1597,18 @@ static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid,
1593 (wid_type != -1 && type != wid_type)) 1597 (wid_type != -1 && type != wid_type))
1594 continue; 1598 continue;
1595 if (__parse_output_path(codec, conn[i], target_dac, 1599 if (__parse_output_path(codec, conn[i], target_dac,
1596 path, depth + 1, AC_WID_AUD_SEL)) { 1600 path, depth + 1, AC_WID_AUD_SEL))
1597 path->path[path->depth] = conn[i]; 1601 goto found;
1598 path->idx[path->depth] = i;
1599 path->depth++;
1600 return true;
1601 }
1602 } 1602 }
1603 return false; 1603 return false;
1604
1605 found:
1606 path->path[path->depth] = conn[i];
1607 path->idx[path->depth] = i;
1608 if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
1609 path->multi[path->depth] = 1;
1610 path->depth++;
1611 return true;
1604} 1612}
1605 1613
1606static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, 1614static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid,
@@ -1634,18 +1642,16 @@ static int via_auto_fill_dac_nids(struct hda_codec *codec)
1634} 1642}
1635 1643
1636static int create_ch_ctls(struct hda_codec *codec, const char *pfx, 1644static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
1637 hda_nid_t pin, hda_nid_t dac, int chs) 1645 int chs, bool check_dac, struct nid_path *path)
1638{ 1646{
1639 struct via_spec *spec = codec->spec; 1647 struct via_spec *spec = codec->spec;
1640 char name[32]; 1648 char name[32];
1641 hda_nid_t nid, sel, conn[8]; 1649 hda_nid_t dac, pin, sel, nid;
1642 int nums, err; 1650 int err;
1643 1651
1644 /* check selector widget connected to the pin */ 1652 dac = check_dac ? path->path[0] : 0;
1645 sel = 0; 1653 pin = path->path[path->depth - 1];
1646 nums = snd_hda_get_connections(codec, pin, conn, ARRAY_SIZE(conn)); 1654 sel = path->depth > 1 ? path->path[1] : 0;
1647 if (nums == 1 && conn[0] != pin)
1648 sel = conn[0];
1649 1655
1650 if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) 1656 if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
1651 nid = dac; 1657 nid = dac;
@@ -1661,6 +1667,7 @@ static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
1661 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); 1667 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
1662 if (err < 0) 1668 if (err < 0)
1663 return err; 1669 return err;
1670 path->vol_ctl = nid;
1664 } 1671 }
1665 1672
1666 if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE)) 1673 if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
@@ -1677,6 +1684,7 @@ static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
1677 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); 1684 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
1678 if (err < 0) 1685 if (err < 0)
1679 return err; 1686 return err;
1687 path->mute_ctl = nid;
1680 } 1688 }
1681 return 0; 1689 return 0;
1682} 1690}
@@ -1747,10 +1755,12 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
1747 if (!pin || !dac) 1755 if (!pin || !dac)
1748 continue; 1756 continue;
1749 if (i == HDA_CLFE) { 1757 if (i == HDA_CLFE) {
1750 err = create_ch_ctls(codec, "Center", pin, dac, 1); 1758 err = create_ch_ctls(codec, "Center", 1, true,
1759 &spec->out_path[i]);
1751 if (err < 0) 1760 if (err < 0)
1752 return err; 1761 return err;
1753 err = create_ch_ctls(codec, "LFE", pin, dac, 2); 1762 err = create_ch_ctls(codec, "LFE", 2, true,
1763 &spec->out_path[i]);
1754 if (err < 0) 1764 if (err < 0)
1755 return err; 1765 return err;
1756 } else { 1766 } else {
@@ -1758,7 +1768,8 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
1758 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && 1768 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
1759 cfg->line_outs == 1) 1769 cfg->line_outs == 1)
1760 pfx = "Speaker"; 1770 pfx = "Speaker";
1761 err = create_ch_ctls(codec, pfx, pin, dac, 3); 1771 err = create_ch_ctls(codec, pfx, 3, true,
1772 &spec->out_path[i]);
1762 if (err < 0) 1773 if (err < 0)
1763 return err; 1774 return err;
1764 } 1775 }
@@ -1790,6 +1801,7 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
1790static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) 1801static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
1791{ 1802{
1792 struct via_spec *spec = codec->spec; 1803 struct via_spec *spec = codec->spec;
1804 struct nid_path *path;
1793 int err; 1805 int err;
1794 1806
1795 if (!pin) 1807 if (!pin)
@@ -1803,9 +1815,17 @@ static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
1803 !spec->hp_dac_nid) 1815 !spec->hp_dac_nid)
1804 return 0; 1816 return 0;
1805 1817
1806 err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3); 1818 if (spec->hp_dac_nid)
1819 path = &spec->hp_path;
1820 else
1821 path = &spec->hp_dep_path;
1822 err = create_ch_ctls(codec, "Headphone", 3, false, path);
1807 if (err < 0) 1823 if (err < 0)
1808 return err; 1824 return err;
1825 if (spec->hp_dac_nid) {
1826 spec->hp_dep_path.vol_ctl = spec->hp_path.vol_ctl;
1827 spec->hp_dep_path.mute_ctl = spec->hp_path.mute_ctl;
1828 }
1809 1829
1810 return 0; 1830 return 0;
1811} 1831}
@@ -1822,11 +1842,13 @@ static int via_auto_create_speaker_ctls(struct hda_codec *codec)
1822 if (parse_output_path(codec, pin, 0, &spec->speaker_path)) { 1842 if (parse_output_path(codec, pin, 0, &spec->speaker_path)) {
1823 dac = spec->speaker_path.path[0]; 1843 dac = spec->speaker_path.path[0];
1824 spec->multiout.extra_out_nid[0] = dac; 1844 spec->multiout.extra_out_nid[0] = dac;
1825 return create_ch_ctls(codec, "Speaker", pin, dac, 3); 1845 return create_ch_ctls(codec, "Speaker", 3, true,
1846 &spec->speaker_path);
1826 } 1847 }
1827 if (parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], 1848 if (parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
1828 &spec->speaker_path)) 1849 &spec->speaker_path))
1829 return create_ch_ctls(codec, "Speaker", pin, 0, 3); 1850 return create_ch_ctls(codec, "Speaker", 3, false,
1851 &spec->speaker_path);
1830 1852
1831 return 0; 1853 return 0;
1832} 1854}