aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorHector Martin <hector@marcansoft.com>2009-06-02 04:54:19 -0400
committerTakashi Iwai <tiwai@suse.de>2009-06-02 04:58:37 -0400
commit3b315d70b094e8b439358756a9084438fd7a71c2 (patch)
tree721ca260820c8d3fcffd6c912e88d062d6e9f927 /sound/pci/hda/patch_realtek.c
parent8871e5b91518a47284b6bc2603b44dbc79c85446 (diff)
ALSA: hda - Acer Aspire 8930G support
Short story: this laptop has 5.1 built-in speakers which you *really* want to use (the not-so-"sub" woofer is what makes the audio above average for a laptop), so 6-channel support is important (plus a decent asound.conf to upmix stereo). It also has the 3 typical jacks that ought to have a selectable mode. And it's based on ALC889, which sucks. Rationale/explanations: The const_channel_count stuff was added because, for a laptop like this, you always have 6 channels available (internal speakers) but still need to set the mode for the 3 external jacks. Therefore, the device always needs to be in 6-channel mode but there still needs to be a mixer control for the jack mode. You could use line/mic-in at the same time as the 6 internal speakers, for example. You might be tempted to make it even smarter by dynamically switching the max channel count when headphones are plugged in (therefore muting the internal speakers and reducing the physical channel count to the jack channel mode), but as a user I consider this to be harmful because I want the audio to blow up to 6 channels / upmixed as soon as I unplug the headphones, and having opened the device while in 2-channel mode would prevent this from working (and always making 6-channel mode available doesn't do any harm). The hardware needs EAPD turned on and the DACs routed to the internal speaker pins, so the patch adds those verbs. The ALC889 CLFE and subsequent (side/aux, here unused) DACs do NOT work by default, at least here. I wasted much time trying to talk to Realtek/pshou about this, but they just kept sending me useless updates to patch_realtek.c that did nothing relevant. In the end I gave up and brute forced the issue by trying to flip every bit in the proprietary coefficient registers, and eventually found the two magic registers that need to be cleared to enable all DACs. I have only heard Acer users complain, but that might be because ALC889 is pretty new and using 5.1 (and noticing the missing center/lfe channels) might not be that common. If this is a generalized issue with all ALC889 systems then those verbs should probably be moved to a common verb array. The internal mic is untested and probably doesn't work. These settings will probably work for other Acer Gemstone laptops with the same 5.1 speaker config. When identified, those should be added to the PCI subsystem ID list. Signed-off-by: Hector Martin <hector@marcansoft.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r--sound/pci/hda/patch_realtek.c99
1 files changed, 94 insertions, 5 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index ad6cc4218049..2bbb9e445cb1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -223,6 +223,7 @@ enum {
223 ALC883_ACER, 223 ALC883_ACER,
224 ALC883_ACER_ASPIRE, 224 ALC883_ACER_ASPIRE,
225 ALC888_ACER_ASPIRE_4930G, 225 ALC888_ACER_ASPIRE_4930G,
226 ALC888_ACER_ASPIRE_8930G,
226 ALC883_MEDION, 227 ALC883_MEDION,
227 ALC883_MEDION_MD2, 228 ALC883_MEDION_MD2,
228 ALC883_LAPTOP_EAPD, 229 ALC883_LAPTOP_EAPD,
@@ -313,6 +314,8 @@ struct alc_spec {
313 const struct hda_channel_mode *channel_mode; 314 const struct hda_channel_mode *channel_mode;
314 int num_channel_mode; 315 int num_channel_mode;
315 int need_dac_fix; 316 int need_dac_fix;
317 int const_channel_count;
318 int ext_channel_count;
316 319
317 /* PCM information */ 320 /* PCM information */
318 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ 321 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
@@ -368,6 +371,7 @@ struct alc_config_preset {
368 unsigned int num_channel_mode; 371 unsigned int num_channel_mode;
369 const struct hda_channel_mode *channel_mode; 372 const struct hda_channel_mode *channel_mode;
370 int need_dac_fix; 373 int need_dac_fix;
374 int const_channel_count;
371 unsigned int num_mux_defs; 375 unsigned int num_mux_defs;
372 const struct hda_input_mux *input_mux; 376 const struct hda_input_mux *input_mux;
373 void (*unsol_event)(struct hda_codec *, unsigned int); 377 void (*unsol_event)(struct hda_codec *, unsigned int);
@@ -462,7 +466,7 @@ static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
462 struct alc_spec *spec = codec->spec; 466 struct alc_spec *spec = codec->spec;
463 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, 467 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
464 spec->num_channel_mode, 468 spec->num_channel_mode,
465 spec->multiout.max_channels); 469 spec->ext_channel_count);
466} 470}
467 471
468static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, 472static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
@@ -472,9 +476,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
472 struct alc_spec *spec = codec->spec; 476 struct alc_spec *spec = codec->spec;
473 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, 477 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
474 spec->num_channel_mode, 478 spec->num_channel_mode,
475 &spec->multiout.max_channels); 479 &spec->ext_channel_count);
476 if (err >= 0 && spec->need_dac_fix) 480 if (err >= 0 && !spec->const_channel_count) {
477 spec->multiout.num_dacs = spec->multiout.max_channels / 2; 481 spec->multiout.max_channels = spec->ext_channel_count;
482 if (spec->need_dac_fix)
483 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
484 }
478 return err; 485 return err;
479} 486}
480 487
@@ -854,8 +861,13 @@ static void setup_preset(struct alc_spec *spec,
854 spec->channel_mode = preset->channel_mode; 861 spec->channel_mode = preset->channel_mode;
855 spec->num_channel_mode = preset->num_channel_mode; 862 spec->num_channel_mode = preset->num_channel_mode;
856 spec->need_dac_fix = preset->need_dac_fix; 863 spec->need_dac_fix = preset->need_dac_fix;
864 spec->const_channel_count = preset->const_channel_count;
857 865
858 spec->multiout.max_channels = spec->channel_mode[0].channels; 866 if (preset->const_channel_count)
867 spec->multiout.max_channels = preset->const_channel_count;
868 else
869 spec->multiout.max_channels = spec->channel_mode[0].channels;
870 spec->ext_channel_count = spec->channel_mode[0].channels;
859 871
860 spec->multiout.num_dacs = preset->num_dacs; 872 spec->multiout.num_dacs = preset->num_dacs;
861 spec->multiout.dac_nids = preset->dac_nids; 873 spec->multiout.dac_nids = preset->dac_nids;
@@ -1456,6 +1468,48 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1456 { } 1468 { }
1457}; 1469};
1458 1470
1471/*
1472 * ALC888 Acer Aspire 8930G model
1473 */
1474
1475static struct hda_verb alc888_acer_aspire_8930g_verbs[] = {
1476/* Front Mic: set to PIN_IN (empty by default) */
1477 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1478/* Unselect Front Mic by default in input mixer 3 */
1479 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1480/* Enable unsolicited event for HP jack */
1481 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1482/* Connect Internal Front to Front */
1483 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1484 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1485 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1486/* Connect Internal Rear to Rear */
1487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1488 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1489 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1490/* Connect Internal CLFE to CLFE */
1491 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1492 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1493 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1494/* Connect HP out to Front */
1495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1496 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1497 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1498/* Enable all DACs */
1499/* DAC DISABLE/MUTE 1? */
1500/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
1501 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
1502 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1503/* DAC DISABLE/MUTE 2? */
1504/* some bit here disables the other DACs. Init=0x4900 */
1505 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
1506 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1507/* Enable amplifiers */
1508 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
1509 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
1510 { }
1511};
1512
1459static struct hda_input_mux alc888_2_capture_sources[2] = { 1513static struct hda_input_mux alc888_2_capture_sources[2] = {
1460 /* Front mic only available on one ADC */ 1514 /* Front mic only available on one ADC */
1461 { 1515 {
@@ -1508,6 +1562,17 @@ static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
1508 alc_automute_amp(codec); 1562 alc_automute_amp(codec);
1509} 1563}
1510 1564
1565static void alc888_acer_aspire_8930g_init_hook(struct hda_codec *codec)
1566{
1567 struct alc_spec *spec = codec->spec;
1568
1569 spec->autocfg.hp_pins[0] = 0x15;
1570 spec->autocfg.speaker_pins[0] = 0x14;
1571 spec->autocfg.speaker_pins[1] = 0x16;
1572 spec->autocfg.speaker_pins[2] = 0x1b;
1573 alc_automute_amp(codec);
1574}
1575
1511/* 1576/*
1512 * ALC880 3-stack model 1577 * ALC880 3-stack model
1513 * 1578 *
@@ -8758,6 +8823,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
8758 [ALC883_ACER] = "acer", 8823 [ALC883_ACER] = "acer",
8759 [ALC883_ACER_ASPIRE] = "acer-aspire", 8824 [ALC883_ACER_ASPIRE] = "acer-aspire",
8760 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", 8825 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
8826 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
8761 [ALC883_MEDION] = "medion", 8827 [ALC883_MEDION] = "medion",
8762 [ALC883_MEDION_MD2] = "medion-md2", 8828 [ALC883_MEDION_MD2] = "medion-md2",
8763 [ALC883_LAPTOP_EAPD] = "laptop-eapd", 8829 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
@@ -8790,6 +8856,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
8790 ALC888_ACER_ASPIRE_4930G), 8856 ALC888_ACER_ASPIRE_4930G),
8791 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", 8857 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
8792 ALC888_ACER_ASPIRE_4930G), 8858 ALC888_ACER_ASPIRE_4930G),
8859 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
8860 ALC888_ACER_ASPIRE_8930G),
8793 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), 8861 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
8794 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), 8862 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
8795 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", 8863 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
@@ -9009,6 +9077,27 @@ static struct alc_config_preset alc883_presets[] = {
9009 .unsol_event = alc_automute_amp_unsol_event, 9077 .unsol_event = alc_automute_amp_unsol_event,
9010 .init_hook = alc888_acer_aspire_4930g_init_hook, 9078 .init_hook = alc888_acer_aspire_4930g_init_hook,
9011 }, 9079 },
9080 [ALC888_ACER_ASPIRE_8930G] = {
9081 .mixers = { alc888_base_mixer,
9082 alc883_chmode_mixer },
9083 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9084 alc888_acer_aspire_8930g_verbs },
9085 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9086 .dac_nids = alc883_dac_nids,
9087 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9088 .adc_nids = alc883_adc_nids_rev,
9089 .capsrc_nids = alc883_capsrc_nids_rev,
9090 .dig_out_nid = ALC883_DIGOUT_NID,
9091 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9092 .channel_mode = alc883_3ST_6ch_modes,
9093 .need_dac_fix = 1,
9094 .const_channel_count = 6,
9095 .num_mux_defs =
9096 ARRAY_SIZE(alc888_2_capture_sources),
9097 .input_mux = alc888_2_capture_sources,
9098 .unsol_event = alc_automute_amp_unsol_event,
9099 .init_hook = alc888_acer_aspire_8930g_init_hook,
9100 },
9012 [ALC883_MEDION] = { 9101 [ALC883_MEDION] = {
9013 .mixers = { alc883_fivestack_mixer, 9102 .mixers = { alc883_fivestack_mixer,
9014 alc883_chmode_mixer }, 9103 alc883_chmode_mixer },