aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-03-12 07:35:27 -0400
committerTakashi Iwai <tiwai@suse.de>2012-03-12 09:52:43 -0400
commit420b0febe54099ea9003bddad0a81e882a8472af (patch)
tree625829e2a6b6958a6ab6ae9e18b5a631b137c4ec /sound/pci/hda/patch_realtek.c
parent2faa3bf15ba69fa12bc53926b88982b3875abb3f (diff)
ALSA: hda - Rewrite the mute-LED control with vmaster hook for ALC269
We've had ugly static handling of the mute-LED with a powersave hook for ALC269 HP laptops just like done in patch_sigmatel.c. This is now rewritten with the new vmaster hook and a fixup code. For that, the new fixup action, ALC_FIXUP_ACT_BUILD, is introduced. It's called after build_controls is called. The reason of this new action is that vmaster hook must be added at this stage (not in init or probe). 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.c82
1 files changed, 44 insertions, 38 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 1de0c1629bab..901547216c4e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -198,6 +198,7 @@ struct alc_spec {
198 198
199 /* for virtual master */ 199 /* for virtual master */
200 hda_nid_t vmaster_nid; 200 hda_nid_t vmaster_nid;
201 struct snd_kcontrol *vmaster_sw_kctl;
201#ifdef CONFIG_SND_HDA_POWER_SAVE 202#ifdef CONFIG_SND_HDA_POWER_SAVE
202 struct hda_loopback_check loopback; 203 struct hda_loopback_check loopback;
203 int num_loopbacks; 204 int num_loopbacks;
@@ -1441,6 +1442,7 @@ enum {
1441 ALC_FIXUP_ACT_PRE_PROBE, 1442 ALC_FIXUP_ACT_PRE_PROBE,
1442 ALC_FIXUP_ACT_PROBE, 1443 ALC_FIXUP_ACT_PROBE,
1443 ALC_FIXUP_ACT_INIT, 1444 ALC_FIXUP_ACT_INIT,
1445 ALC_FIXUP_ACT_BUILD,
1444}; 1446};
1445 1447
1446static void alc_apply_fixup(struct hda_codec *codec, int action) 1448static void alc_apply_fixup(struct hda_codec *codec, int action)
@@ -1955,9 +1957,10 @@ static int __alc_build_controls(struct hda_codec *codec)
1955 } 1957 }
1956 if (!spec->no_analog && 1958 if (!spec->no_analog &&
1957 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 1959 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1958 err = snd_hda_add_vmaster(codec, "Master Playback Switch", 1960 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
1959 NULL, alc_slave_pfxs, 1961 NULL, alc_slave_pfxs,
1960 "Playback Switch"); 1962 "Playback Switch",
1963 true, &spec->vmaster_sw_kctl);
1961 if (err < 0) 1964 if (err < 0)
1962 return err; 1965 return err;
1963 } 1966 }
@@ -2042,7 +2045,11 @@ static int alc_build_controls(struct hda_codec *codec)
2042 int err = __alc_build_controls(codec); 2045 int err = __alc_build_controls(codec);
2043 if (err < 0) 2046 if (err < 0)
2044 return err; 2047 return err;
2045 return snd_hda_jack_add_kctls(codec, &spec->autocfg); 2048 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
2049 if (err < 0)
2050 return err;
2051 alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD);
2052 return 0;
2046} 2053}
2047 2054
2048 2055
@@ -5721,35 +5728,6 @@ static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
5721 /* NID is set in alc_build_pcms */ 5728 /* NID is set in alc_build_pcms */
5722}; 5729};
5723 5730
5724#ifdef CONFIG_SND_HDA_POWER_SAVE
5725static int alc269_mic2_for_mute_led(struct hda_codec *codec)
5726{
5727 switch (codec->subsystem_id) {
5728 case 0x103c1586:
5729 return 1;
5730 }
5731 return 0;
5732}
5733
5734static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
5735{
5736 /* update mute-LED according to the speaker mute state */
5737 if (nid == 0x01 || nid == 0x14) {
5738 int pinval;
5739 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
5740 HDA_AMP_MUTE)
5741 pinval = 0x24;
5742 else
5743 pinval = 0x20;
5744 /* mic2 vref pin is used for mute LED control */
5745 snd_hda_codec_update_cache(codec, 0x19, 0,
5746 AC_VERB_SET_PIN_WIDGET_CONTROL,
5747 pinval);
5748 }
5749 return alc_check_power_status(codec, nid);
5750}
5751#endif /* CONFIG_SND_HDA_POWER_SAVE */
5752
5753/* different alc269-variants */ 5731/* different alc269-variants */
5754enum { 5732enum {
5755 ALC269_TYPE_ALC269VA, 5733 ALC269_TYPE_ALC269VA,
@@ -5900,6 +5878,33 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec,
5900 spec->automute_hook = alc269_quanta_automute; 5878 spec->automute_hook = alc269_quanta_automute;
5901} 5879}
5902 5880
5881/* update mute-LED according to the speaker mute state via mic2 VREF pin */
5882static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
5883{
5884 struct hda_codec *codec = private_data;
5885 unsigned int pinval = enabled ? 0x20 : 0x24;
5886 snd_hda_codec_update_cache(codec, 0x19, 0,
5887 AC_VERB_SET_PIN_WIDGET_CONTROL,
5888 pinval);
5889}
5890
5891static void alc269_fixup_mic2_mute(struct hda_codec *codec,
5892 const struct alc_fixup *fix, int action)
5893{
5894 struct alc_spec *spec = codec->spec;
5895 switch (action) {
5896 case ALC_FIXUP_ACT_BUILD:
5897 if (!spec->vmaster_sw_kctl)
5898 return;
5899 snd_ctl_add_vmaster_hook(spec->vmaster_sw_kctl,
5900 alc269_fixup_mic2_mute_hook, codec);
5901 /* fallthru */
5902 case ALC_FIXUP_ACT_INIT:
5903 snd_ctl_sync_vmaster_hook(spec->vmaster_sw_kctl);
5904 break;
5905 }
5906}
5907
5903enum { 5908enum {
5904 ALC269_FIXUP_SONY_VAIO, 5909 ALC269_FIXUP_SONY_VAIO,
5905 ALC275_FIXUP_SONY_VAIO_GPIO2, 5910 ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -5917,6 +5922,7 @@ enum {
5917 ALC269_FIXUP_DMIC, 5922 ALC269_FIXUP_DMIC,
5918 ALC269VB_FIXUP_AMIC, 5923 ALC269VB_FIXUP_AMIC,
5919 ALC269VB_FIXUP_DMIC, 5924 ALC269VB_FIXUP_DMIC,
5925 ALC269_FIXUP_MIC2_MUTE_LED,
5920}; 5926};
5921 5927
5922static const struct alc_fixup alc269_fixups[] = { 5928static const struct alc_fixup alc269_fixups[] = {
@@ -6037,9 +6043,14 @@ static const struct alc_fixup alc269_fixups[] = {
6037 { } 6043 { }
6038 }, 6044 },
6039 }, 6045 },
6046 [ALC269_FIXUP_MIC2_MUTE_LED] = {
6047 .type = ALC_FIXUP_FUNC,
6048 .v.func = alc269_fixup_mic2_mute,
6049 },
6040}; 6050};
6041 6051
6042static const struct snd_pci_quirk alc269_fixup_tbl[] = { 6052static const struct snd_pci_quirk alc269_fixup_tbl[] = {
6053 SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
6043 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), 6054 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
6044 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), 6055 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
6045 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), 6056 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
@@ -6231,11 +6242,6 @@ static int patch_alc269(struct hda_codec *codec)
6231#endif 6242#endif
6232 spec->shutup = alc269_shutup; 6243 spec->shutup = alc269_shutup;
6233 6244
6234#ifdef CONFIG_SND_HDA_POWER_SAVE
6235 if (alc269_mic2_for_mute_led(codec))
6236 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
6237#endif
6238
6239 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); 6245 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
6240 6246
6241 return 0; 6247 return 0;