diff options
-rw-r--r-- | Documentation/sound/alsa/HD-Audio-Models.txt | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 32 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 75 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 339 |
4 files changed, 436 insertions, 16 deletions
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 1d38b0dfba95..03771d7c5dd7 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt | |||
@@ -114,6 +114,11 @@ ALC662/663/272 | |||
114 | samsung-nc10 Samsung NC10 mini notebook | 114 | samsung-nc10 Samsung NC10 mini notebook |
115 | auto auto-config reading BIOS (default) | 115 | auto auto-config reading BIOS (default) |
116 | 116 | ||
117 | ALC680 | ||
118 | ====== | ||
119 | base Base model (ASUS NX90) | ||
120 | auto auto-config reading BIOS (default) | ||
121 | |||
117 | ALC882/883/885/888/889 | 122 | ALC882/883/885/888/889 |
118 | ====================== | 123 | ====================== |
119 | 3stack-dig 3-jack with SPDIF I/O | 124 | 3stack-dig 3-jack with SPDIF I/O |
@@ -282,6 +287,7 @@ Conexant 5051 | |||
282 | hp HP Spartan laptop | 287 | hp HP Spartan laptop |
283 | hp-dv6736 HP dv6736 | 288 | hp-dv6736 HP dv6736 |
284 | hp-f700 HP Compaq Presario F700 | 289 | hp-f700 HP Compaq Presario F700 |
290 | ideapad Lenovo IdeaPad laptop | ||
285 | lenovo-x200 Lenovo X200 laptop | 291 | lenovo-x200 Lenovo X200 laptop |
286 | toshiba Toshiba Satellite M300 | 292 | toshiba Toshiba Satellite M300 |
287 | 293 | ||
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ba2098d20ccc..501cbc411a83 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1565,6 +1565,17 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) | |||
1565 | EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); | 1565 | EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); |
1566 | #endif /* SND_HDA_NEEDS_RESUME */ | 1566 | #endif /* SND_HDA_NEEDS_RESUME */ |
1567 | 1567 | ||
1568 | static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
1569 | unsigned int ofs) | ||
1570 | { | ||
1571 | u32 caps = query_amp_caps(codec, nid, dir); | ||
1572 | /* get num steps */ | ||
1573 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1574 | if (ofs < caps) | ||
1575 | caps -= ofs; | ||
1576 | return caps; | ||
1577 | } | ||
1578 | |||
1568 | /** | 1579 | /** |
1569 | * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer | 1580 | * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer |
1570 | * | 1581 | * |
@@ -1579,23 +1590,17 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | |||
1579 | u8 chs = get_amp_channels(kcontrol); | 1590 | u8 chs = get_amp_channels(kcontrol); |
1580 | int dir = get_amp_direction(kcontrol); | 1591 | int dir = get_amp_direction(kcontrol); |
1581 | unsigned int ofs = get_amp_offset(kcontrol); | 1592 | unsigned int ofs = get_amp_offset(kcontrol); |
1582 | u32 caps; | ||
1583 | 1593 | ||
1584 | caps = query_amp_caps(codec, nid, dir); | 1594 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1585 | /* num steps */ | 1595 | uinfo->count = chs == 3 ? 2 : 1; |
1586 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | 1596 | uinfo->value.integer.min = 0; |
1587 | if (!caps) { | 1597 | uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs); |
1598 | if (!uinfo->value.integer.max) { | ||
1588 | printk(KERN_WARNING "hda_codec: " | 1599 | printk(KERN_WARNING "hda_codec: " |
1589 | "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, | 1600 | "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, |
1590 | kcontrol->id.name); | 1601 | kcontrol->id.name); |
1591 | return -EINVAL; | 1602 | return -EINVAL; |
1592 | } | 1603 | } |
1593 | if (ofs < caps) | ||
1594 | caps -= ofs; | ||
1595 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1596 | uinfo->count = chs == 3 ? 2 : 1; | ||
1597 | uinfo->value.integer.min = 0; | ||
1598 | uinfo->value.integer.max = caps; | ||
1599 | return 0; | 1604 | return 0; |
1600 | } | 1605 | } |
1601 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); | 1606 | EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); |
@@ -1620,8 +1625,13 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, | |||
1620 | int ch, int dir, int idx, unsigned int ofs, | 1625 | int ch, int dir, int idx, unsigned int ofs, |
1621 | unsigned int val) | 1626 | unsigned int val) |
1622 | { | 1627 | { |
1628 | unsigned int maxval; | ||
1629 | |||
1623 | if (val > 0) | 1630 | if (val > 0) |
1624 | val += ofs; | 1631 | val += ofs; |
1632 | maxval = get_amp_max_value(codec, nid, dir, ofs); | ||
1633 | if (val > maxval) | ||
1634 | val = maxval; | ||
1625 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, | 1635 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, |
1626 | HDA_AMP_VOLMASK, val); | 1636 | HDA_AMP_VOLMASK, val); |
1627 | } | 1637 | } |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 2bf2cb5da956..3b789ee548b4 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -131,6 +131,8 @@ struct conexant_spec { | |||
131 | unsigned int dc_enable; | 131 | unsigned int dc_enable; |
132 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ | 132 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ |
133 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ | 133 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ |
134 | |||
135 | unsigned int beep_amp; | ||
134 | }; | 136 | }; |
135 | 137 | ||
136 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 138 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -515,6 +517,15 @@ static struct snd_kcontrol_new cxt_capture_mixers[] = { | |||
515 | {} | 517 | {} |
516 | }; | 518 | }; |
517 | 519 | ||
520 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
521 | /* additional beep mixers; the actual parameters are overwritten at build */ | ||
522 | static struct snd_kcontrol_new cxt_beep_mixer[] = { | ||
523 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), | ||
524 | HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), | ||
525 | { } /* end */ | ||
526 | }; | ||
527 | #endif | ||
528 | |||
518 | static const char *slave_vols[] = { | 529 | static const char *slave_vols[] = { |
519 | "Headphone Playback Volume", | 530 | "Headphone Playback Volume", |
520 | "Speaker Playback Volume", | 531 | "Speaker Playback Volume", |
@@ -580,6 +591,23 @@ static int conexant_build_controls(struct hda_codec *codec) | |||
580 | return err; | 591 | return err; |
581 | } | 592 | } |
582 | 593 | ||
594 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
595 | /* create beep controls if needed */ | ||
596 | if (spec->beep_amp) { | ||
597 | struct snd_kcontrol_new *knew; | ||
598 | for (knew = cxt_beep_mixer; knew->name; knew++) { | ||
599 | struct snd_kcontrol *kctl; | ||
600 | kctl = snd_ctl_new1(knew, codec); | ||
601 | if (!kctl) | ||
602 | return -ENOMEM; | ||
603 | kctl->private_value = spec->beep_amp; | ||
604 | err = snd_hda_ctl_add(codec, 0, kctl); | ||
605 | if (err < 0) | ||
606 | return err; | ||
607 | } | ||
608 | } | ||
609 | #endif | ||
610 | |||
583 | return 0; | 611 | return 0; |
584 | } | 612 | } |
585 | 613 | ||
@@ -590,6 +618,13 @@ static struct hda_codec_ops conexant_patch_ops = { | |||
590 | .free = conexant_free, | 618 | .free = conexant_free, |
591 | }; | 619 | }; |
592 | 620 | ||
621 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
622 | #define set_beep_amp(spec, nid, idx, dir) \ | ||
623 | ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) | ||
624 | #else | ||
625 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ | ||
626 | #endif | ||
627 | |||
593 | /* | 628 | /* |
594 | * EAPD control | 629 | * EAPD control |
595 | * the private value = nid | (invert << 8) | 630 | * the private value = nid | (invert << 8) |
@@ -1130,9 +1165,10 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1130 | spec->num_init_verbs = 1; | 1165 | spec->num_init_verbs = 1; |
1131 | spec->init_verbs[0] = cxt5045_init_verbs; | 1166 | spec->init_verbs[0] = cxt5045_init_verbs; |
1132 | spec->spdif_route = 0; | 1167 | spec->spdif_route = 0; |
1133 | spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes), | 1168 | spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); |
1134 | spec->channel_mode = cxt5045_modes, | 1169 | spec->channel_mode = cxt5045_modes; |
1135 | 1170 | ||
1171 | set_beep_amp(spec, 0x16, 0, 1); | ||
1136 | 1172 | ||
1137 | codec->patch_ops = conexant_patch_ops; | 1173 | codec->patch_ops = conexant_patch_ops; |
1138 | 1174 | ||
@@ -1211,6 +1247,9 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1211 | break; | 1247 | break; |
1212 | } | 1248 | } |
1213 | 1249 | ||
1250 | if (spec->beep_amp) | ||
1251 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
1252 | |||
1214 | return 0; | 1253 | return 0; |
1215 | } | 1254 | } |
1216 | 1255 | ||
@@ -1632,6 +1671,11 @@ static void cxt5051_update_speaker(struct hda_codec *codec) | |||
1632 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 1671 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
1633 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1672 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
1634 | pinctl); | 1673 | pinctl); |
1674 | /* on ideapad there is an aditional speaker (subwoofer) to mute */ | ||
1675 | if (spec->ideapad) | ||
1676 | snd_hda_codec_write(codec, 0x1b, 0, | ||
1677 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1678 | pinctl); | ||
1635 | } | 1679 | } |
1636 | 1680 | ||
1637 | /* turn on/off EAPD (+ mute HP) as a master switch */ | 1681 | /* turn on/off EAPD (+ mute HP) as a master switch */ |
@@ -1888,6 +1932,13 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, | |||
1888 | #endif | 1932 | #endif |
1889 | } | 1933 | } |
1890 | 1934 | ||
1935 | static struct hda_verb cxt5051_ideapad_init_verbs[] = { | ||
1936 | /* Subwoofer */ | ||
1937 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1938 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1939 | { } /* end */ | ||
1940 | }; | ||
1941 | |||
1891 | /* initialize jack-sensing, too */ | 1942 | /* initialize jack-sensing, too */ |
1892 | static int cxt5051_init(struct hda_codec *codec) | 1943 | static int cxt5051_init(struct hda_codec *codec) |
1893 | { | 1944 | { |
@@ -1917,6 +1968,7 @@ enum { | |||
1917 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ | 1968 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ |
1918 | CXT5051_F700, /* HP Compaq Presario F700 */ | 1969 | CXT5051_F700, /* HP Compaq Presario F700 */ |
1919 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | 1970 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ |
1971 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ | ||
1920 | CXT5051_MODELS | 1972 | CXT5051_MODELS |
1921 | }; | 1973 | }; |
1922 | 1974 | ||
@@ -1927,6 +1979,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1927 | [CXT5051_LENOVO_X200] = "lenovo-x200", | 1979 | [CXT5051_LENOVO_X200] = "lenovo-x200", |
1928 | [CXT5051_F700] = "hp-700", | 1980 | [CXT5051_F700] = "hp-700", |
1929 | [CXT5051_TOSHIBA] = "toshiba", | 1981 | [CXT5051_TOSHIBA] = "toshiba", |
1982 | [CXT5051_IDEAPAD] = "ideapad", | ||
1930 | }; | 1983 | }; |
1931 | 1984 | ||
1932 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1985 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
@@ -1938,6 +1991,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | |||
1938 | CXT5051_LAPTOP), | 1991 | CXT5051_LAPTOP), |
1939 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 1992 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
1940 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), | 1993 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), |
1994 | SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), | ||
1941 | {} | 1995 | {} |
1942 | }; | 1996 | }; |
1943 | 1997 | ||
@@ -1972,6 +2026,8 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1972 | spec->cur_adc = 0; | 2026 | spec->cur_adc = 0; |
1973 | spec->cur_adc_idx = 0; | 2027 | spec->cur_adc_idx = 0; |
1974 | 2028 | ||
2029 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); | ||
2030 | |||
1975 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | 2031 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; |
1976 | 2032 | ||
1977 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | 2033 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, |
@@ -1999,8 +2055,16 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1999 | spec->mixers[0] = cxt5051_toshiba_mixers; | 2055 | spec->mixers[0] = cxt5051_toshiba_mixers; |
2000 | spec->auto_mic = AUTO_MIC_PORTB; | 2056 | spec->auto_mic = AUTO_MIC_PORTB; |
2001 | break; | 2057 | break; |
2058 | case CXT5051_IDEAPAD: | ||
2059 | spec->init_verbs[spec->num_init_verbs++] = | ||
2060 | cxt5051_ideapad_init_verbs; | ||
2061 | spec->ideapad = 1; | ||
2062 | break; | ||
2002 | } | 2063 | } |
2003 | 2064 | ||
2065 | if (spec->beep_amp) | ||
2066 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
2067 | |||
2004 | return 0; | 2068 | return 0; |
2005 | } | 2069 | } |
2006 | 2070 | ||
@@ -2616,7 +2680,6 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | |||
2616 | .put = cxt5066_mic_boost_mux_enum_put, | 2680 | .put = cxt5066_mic_boost_mux_enum_put, |
2617 | .private_value = 0x23 | 0x100, | 2681 | .private_value = 0x23 | 0x100, |
2618 | }, | 2682 | }, |
2619 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
2620 | {} | 2683 | {} |
2621 | }; | 2684 | }; |
2622 | 2685 | ||
@@ -3014,6 +3077,8 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3014 | spec->cur_adc = 0; | 3077 | spec->cur_adc = 0; |
3015 | spec->cur_adc_idx = 0; | 3078 | spec->cur_adc_idx = 0; |
3016 | 3079 | ||
3080 | set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); | ||
3081 | |||
3017 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | 3082 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, |
3018 | cxt5066_models, cxt5066_cfg_tbl); | 3083 | cxt5066_models, cxt5066_cfg_tbl); |
3019 | switch (board_config) { | 3084 | switch (board_config) { |
@@ -3062,7 +3127,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3062 | spec->port_d_mode = 0; | 3127 | spec->port_d_mode = 0; |
3063 | spec->dell_vostro = 1; | 3128 | spec->dell_vostro = 1; |
3064 | spec->mic_boost = 3; /* default 30dB gain */ | 3129 | spec->mic_boost = 3; /* default 30dB gain */ |
3065 | snd_hda_attach_beep_device(codec, 0x13); | ||
3066 | 3130 | ||
3067 | /* no S/PDIF out */ | 3131 | /* no S/PDIF out */ |
3068 | spec->multiout.dig_out_nid = 0; | 3132 | spec->multiout.dig_out_nid = 0; |
@@ -3104,6 +3168,9 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3104 | break; | 3168 | break; |
3105 | } | 3169 | } |
3106 | 3170 | ||
3171 | if (spec->beep_amp) | ||
3172 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
3173 | |||
3107 | return 0; | 3174 | return 0; |
3108 | } | 3175 | } |
3109 | 3176 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ff614dd824c1..a7592f5e97d4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -256,6 +256,13 @@ enum { | |||
256 | ALC882_MODEL_LAST, | 256 | ALC882_MODEL_LAST, |
257 | }; | 257 | }; |
258 | 258 | ||
259 | /* ALC680 models */ | ||
260 | enum { | ||
261 | ALC680_BASE, | ||
262 | ALC680_AUTO, | ||
263 | ALC680_MODEL_LAST, | ||
264 | }; | ||
265 | |||
259 | /* for GPIO Poll */ | 266 | /* for GPIO Poll */ |
260 | #define GPIO_MASK 0x03 | 267 | #define GPIO_MASK 0x03 |
261 | 268 | ||
@@ -18615,7 +18622,7 @@ static int alc662_parse_auto_config(struct hda_codec *codec) | |||
18615 | 18622 | ||
18616 | add_verb(spec, alc662_init_verbs); | 18623 | add_verb(spec, alc662_init_verbs); |
18617 | if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || | 18624 | if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || |
18618 | codec->vendor_id == 0x10ec0665) | 18625 | codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) |
18619 | add_verb(spec, alc663_init_verbs); | 18626 | add_verb(spec, alc663_init_verbs); |
18620 | 18627 | ||
18621 | if (codec->vendor_id == 0x10ec0272) | 18628 | if (codec->vendor_id == 0x10ec0272) |
@@ -18759,6 +18766,335 @@ static int patch_alc888(struct hda_codec *codec) | |||
18759 | } | 18766 | } |
18760 | 18767 | ||
18761 | /* | 18768 | /* |
18769 | * ALC680 support | ||
18770 | */ | ||
18771 | #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID | ||
18772 | #define alc680_modes alc260_modes | ||
18773 | |||
18774 | static hda_nid_t alc680_dac_nids[3] = { | ||
18775 | /* Lout1, Lout2, hp */ | ||
18776 | 0x02, 0x03, 0x04 | ||
18777 | }; | ||
18778 | |||
18779 | static hda_nid_t alc680_adc_nids[3] = { | ||
18780 | /* ADC0-2 */ | ||
18781 | /* DMIC, MIC, Line-in*/ | ||
18782 | 0x07, 0x08, 0x09 | ||
18783 | }; | ||
18784 | |||
18785 | static struct snd_kcontrol_new alc680_base_mixer[] = { | ||
18786 | /* output mixer control */ | ||
18787 | HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
18788 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
18789 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), | ||
18790 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
18791 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
18792 | { } | ||
18793 | }; | ||
18794 | |||
18795 | static struct snd_kcontrol_new alc680_capture_mixer[] = { | ||
18796 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
18797 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
18798 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
18799 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
18800 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | ||
18801 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | ||
18802 | { } /* end */ | ||
18803 | }; | ||
18804 | |||
18805 | /* | ||
18806 | * generic initialization of ADC, input mixers and output mixers | ||
18807 | */ | ||
18808 | static struct hda_verb alc680_init_verbs[] = { | ||
18809 | /* Unmute DAC0-1 and set vol = 0 */ | ||
18810 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
18811 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
18812 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
18813 | |||
18814 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
18815 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
18816 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | ||
18817 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
18818 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
18819 | |||
18820 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
18821 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
18822 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
18823 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
18824 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
18825 | { } | ||
18826 | }; | ||
18827 | |||
18828 | /* create input playback/capture controls for the given pin */ | ||
18829 | static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | ||
18830 | const char *ctlname, int idx) | ||
18831 | { | ||
18832 | hda_nid_t dac; | ||
18833 | int err; | ||
18834 | |||
18835 | switch (nid) { | ||
18836 | case 0x14: | ||
18837 | dac = 0x02; | ||
18838 | break; | ||
18839 | case 0x15: | ||
18840 | dac = 0x03; | ||
18841 | break; | ||
18842 | case 0x16: | ||
18843 | dac = 0x04; | ||
18844 | break; | ||
18845 | default: | ||
18846 | return 0; | ||
18847 | } | ||
18848 | if (spec->multiout.dac_nids[0] != dac && | ||
18849 | spec->multiout.dac_nids[1] != dac) { | ||
18850 | err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, | ||
18851 | HDA_COMPOSE_AMP_VAL(dac, 3, idx, | ||
18852 | HDA_OUTPUT)); | ||
18853 | if (err < 0) | ||
18854 | return err; | ||
18855 | |||
18856 | err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, | ||
18857 | HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); | ||
18858 | |||
18859 | if (err < 0) | ||
18860 | return err; | ||
18861 | spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; | ||
18862 | } | ||
18863 | |||
18864 | return 0; | ||
18865 | } | ||
18866 | |||
18867 | /* add playback controls from the parsed DAC table */ | ||
18868 | static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
18869 | const struct auto_pin_cfg *cfg) | ||
18870 | { | ||
18871 | hda_nid_t nid; | ||
18872 | int err; | ||
18873 | |||
18874 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
18875 | |||
18876 | nid = cfg->line_out_pins[0]; | ||
18877 | if (nid) { | ||
18878 | const char *name; | ||
18879 | if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
18880 | name = "Speaker"; | ||
18881 | else | ||
18882 | name = "Front"; | ||
18883 | err = alc680_new_analog_output(spec, nid, name, 0); | ||
18884 | if (err < 0) | ||
18885 | return err; | ||
18886 | } | ||
18887 | |||
18888 | nid = cfg->speaker_pins[0]; | ||
18889 | if (nid) { | ||
18890 | err = alc680_new_analog_output(spec, nid, "Speaker", 0); | ||
18891 | if (err < 0) | ||
18892 | return err; | ||
18893 | } | ||
18894 | nid = cfg->hp_pins[0]; | ||
18895 | if (nid) { | ||
18896 | err = alc680_new_analog_output(spec, nid, "Headphone", 0); | ||
18897 | if (err < 0) | ||
18898 | return err; | ||
18899 | } | ||
18900 | |||
18901 | return 0; | ||
18902 | } | ||
18903 | |||
18904 | static void alc680_auto_set_output_and_unmute(struct hda_codec *codec, | ||
18905 | hda_nid_t nid, int pin_type) | ||
18906 | { | ||
18907 | alc_set_pin_output(codec, nid, pin_type); | ||
18908 | } | ||
18909 | |||
18910 | static void alc680_auto_init_multi_out(struct hda_codec *codec) | ||
18911 | { | ||
18912 | struct alc_spec *spec = codec->spec; | ||
18913 | hda_nid_t nid = spec->autocfg.line_out_pins[0]; | ||
18914 | if (nid) { | ||
18915 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | ||
18916 | alc680_auto_set_output_and_unmute(codec, nid, pin_type); | ||
18917 | } | ||
18918 | } | ||
18919 | |||
18920 | static void alc680_auto_init_hp_out(struct hda_codec *codec) | ||
18921 | { | ||
18922 | struct alc_spec *spec = codec->spec; | ||
18923 | hda_nid_t pin; | ||
18924 | |||
18925 | pin = spec->autocfg.hp_pins[0]; | ||
18926 | if (pin) | ||
18927 | alc680_auto_set_output_and_unmute(codec, pin, PIN_HP); | ||
18928 | pin = spec->autocfg.speaker_pins[0]; | ||
18929 | if (pin) | ||
18930 | alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT); | ||
18931 | } | ||
18932 | |||
18933 | /* pcm configuration: identical with ALC880 */ | ||
18934 | #define alc680_pcm_analog_playback alc880_pcm_analog_playback | ||
18935 | #define alc680_pcm_analog_capture alc880_pcm_analog_capture | ||
18936 | #define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
18937 | #define alc680_pcm_digital_playback alc880_pcm_digital_playback | ||
18938 | |||
18939 | static struct hda_input_mux alc680_capture_source = { | ||
18940 | .num_items = 1, | ||
18941 | .items = { | ||
18942 | { "Mic", 0x0 }, | ||
18943 | }, | ||
18944 | }; | ||
18945 | |||
18946 | /* | ||
18947 | * BIOS auto configuration | ||
18948 | */ | ||
18949 | static int alc680_parse_auto_config(struct hda_codec *codec) | ||
18950 | { | ||
18951 | struct alc_spec *spec = codec->spec; | ||
18952 | int err; | ||
18953 | static hda_nid_t alc680_ignore[] = { 0 }; | ||
18954 | |||
18955 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
18956 | alc680_ignore); | ||
18957 | if (err < 0) | ||
18958 | return err; | ||
18959 | if (!spec->autocfg.line_outs) { | ||
18960 | if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { | ||
18961 | spec->multiout.max_channels = 2; | ||
18962 | spec->no_analog = 1; | ||
18963 | goto dig_only; | ||
18964 | } | ||
18965 | return 0; /* can't find valid BIOS pin config */ | ||
18966 | } | ||
18967 | err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
18968 | if (err < 0) | ||
18969 | return err; | ||
18970 | |||
18971 | spec->multiout.max_channels = 2; | ||
18972 | |||
18973 | dig_only: | ||
18974 | /* digital only support output */ | ||
18975 | if (spec->autocfg.dig_outs) { | ||
18976 | spec->multiout.dig_out_nid = ALC680_DIGOUT_NID; | ||
18977 | spec->dig_out_type = spec->autocfg.dig_out_type[0]; | ||
18978 | } | ||
18979 | if (spec->kctls.list) | ||
18980 | add_mixer(spec, spec->kctls.list); | ||
18981 | |||
18982 | add_verb(spec, alc680_init_verbs); | ||
18983 | spec->num_mux_defs = 1; | ||
18984 | spec->input_mux = &alc680_capture_source; | ||
18985 | |||
18986 | err = alc_auto_add_mic_boost(codec); | ||
18987 | if (err < 0) | ||
18988 | return err; | ||
18989 | |||
18990 | return 1; | ||
18991 | } | ||
18992 | |||
18993 | #define alc680_auto_init_analog_input alc882_auto_init_analog_input | ||
18994 | |||
18995 | /* init callback for auto-configuration model -- overriding the default init */ | ||
18996 | static void alc680_auto_init(struct hda_codec *codec) | ||
18997 | { | ||
18998 | struct alc_spec *spec = codec->spec; | ||
18999 | alc680_auto_init_multi_out(codec); | ||
19000 | alc680_auto_init_hp_out(codec); | ||
19001 | alc680_auto_init_analog_input(codec); | ||
19002 | if (spec->unsol_event) | ||
19003 | alc_inithook(codec); | ||
19004 | } | ||
19005 | |||
19006 | /* | ||
19007 | * configuration and preset | ||
19008 | */ | ||
19009 | static const char *alc680_models[ALC680_MODEL_LAST] = { | ||
19010 | [ALC680_BASE] = "base", | ||
19011 | [ALC680_AUTO] = "auto", | ||
19012 | }; | ||
19013 | |||
19014 | static struct snd_pci_quirk alc680_cfg_tbl[] = { | ||
19015 | SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE), | ||
19016 | {} | ||
19017 | }; | ||
19018 | |||
19019 | static struct alc_config_preset alc680_presets[] = { | ||
19020 | [ALC680_BASE] = { | ||
19021 | .mixers = { alc680_base_mixer }, | ||
19022 | .cap_mixer = alc680_capture_mixer, | ||
19023 | .init_verbs = { alc680_init_verbs }, | ||
19024 | .num_dacs = ARRAY_SIZE(alc680_dac_nids), | ||
19025 | .dac_nids = alc680_dac_nids, | ||
19026 | .num_adc_nids = ARRAY_SIZE(alc680_adc_nids), | ||
19027 | .adc_nids = alc680_adc_nids, | ||
19028 | .hp_nid = 0x04, | ||
19029 | .dig_out_nid = ALC680_DIGOUT_NID, | ||
19030 | .num_channel_mode = ARRAY_SIZE(alc680_modes), | ||
19031 | .channel_mode = alc680_modes, | ||
19032 | .input_mux = &alc680_capture_source, | ||
19033 | }, | ||
19034 | }; | ||
19035 | |||
19036 | static int patch_alc680(struct hda_codec *codec) | ||
19037 | { | ||
19038 | struct alc_spec *spec; | ||
19039 | int board_config; | ||
19040 | int err; | ||
19041 | |||
19042 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
19043 | if (spec == NULL) | ||
19044 | return -ENOMEM; | ||
19045 | |||
19046 | codec->spec = spec; | ||
19047 | |||
19048 | board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST, | ||
19049 | alc680_models, | ||
19050 | alc680_cfg_tbl); | ||
19051 | |||
19052 | if (board_config < 0 || board_config >= ALC680_MODEL_LAST) { | ||
19053 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
19054 | codec->chip_name); | ||
19055 | board_config = ALC680_AUTO; | ||
19056 | } | ||
19057 | |||
19058 | if (board_config == ALC680_AUTO) { | ||
19059 | /* automatic parse from the BIOS config */ | ||
19060 | err = alc680_parse_auto_config(codec); | ||
19061 | if (err < 0) { | ||
19062 | alc_free(codec); | ||
19063 | return err; | ||
19064 | } else if (!err) { | ||
19065 | printk(KERN_INFO | ||
19066 | "hda_codec: Cannot set up configuration " | ||
19067 | "from BIOS. Using base mode...\n"); | ||
19068 | board_config = ALC680_BASE; | ||
19069 | } | ||
19070 | } | ||
19071 | |||
19072 | if (board_config != ALC680_AUTO) | ||
19073 | setup_preset(codec, &alc680_presets[board_config]); | ||
19074 | |||
19075 | spec->stream_analog_playback = &alc680_pcm_analog_playback; | ||
19076 | spec->stream_analog_capture = &alc680_pcm_analog_capture; | ||
19077 | spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture; | ||
19078 | spec->stream_digital_playback = &alc680_pcm_digital_playback; | ||
19079 | |||
19080 | if (!spec->adc_nids) { | ||
19081 | spec->adc_nids = alc680_adc_nids; | ||
19082 | spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids); | ||
19083 | } | ||
19084 | |||
19085 | if (!spec->cap_mixer) | ||
19086 | set_capture_mixer(codec); | ||
19087 | |||
19088 | spec->vmaster_nid = 0x02; | ||
19089 | |||
19090 | codec->patch_ops = alc_patch_ops; | ||
19091 | if (board_config == ALC680_AUTO) | ||
19092 | spec->init_hook = alc680_auto_init; | ||
19093 | |||
19094 | return 0; | ||
19095 | } | ||
19096 | |||
19097 | /* | ||
18762 | * patch entries | 19098 | * patch entries |
18763 | */ | 19099 | */ |
18764 | static struct hda_codec_preset snd_hda_preset_realtek[] = { | 19100 | static struct hda_codec_preset snd_hda_preset_realtek[] = { |
@@ -18782,6 +19118,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
18782 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, | 19118 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, |
18783 | { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, | 19119 | { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, |
18784 | { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, | 19120 | { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, |
19121 | { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, | ||
18785 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 19122 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, |
18786 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 19123 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
18787 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, | 19124 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, |