From a5ce88909d3007caa7b65996a8f6784350beb2a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Jul 2007 15:42:26 +0200 Subject: [ALSA] Clean up with common snd_ctl_boolean_*_info callbacks Clean up codes using the new common snd_ctl_boolean_*_info() callbacks. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 10 +--------- sound/pci/hda/patch_analog.c | 10 +--------- sound/pci/hda/patch_conexant.c | 10 +--------- sound/pci/hda/patch_realtek.c | 20 ++------------------ sound/pci/hda/patch_si3054.c | 10 +--------- sound/pci/hda/patch_sigmatel.c | 9 +-------- 6 files changed, 7 insertions(+), 62 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f87f8f088956..a05db2f214bd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1129,15 +1129,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static int snd_hda_spdif_out_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4d7f8d11ad75..fafadf9fab8e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -350,15 +350,7 @@ static struct hda_codec_ops ad198x_patch_ops = { * EAPD control * the private value = nid | (invert << 8) */ -static int ad198x_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define ad198x_eapd_info snd_ctl_boolean_mono_info static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4d8e8af5c819..26034315197f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -368,15 +368,7 @@ static struct hda_codec_ops conexant_patch_ops = { * the private value = nid | (invert << 8) */ -static int cxt_eapd_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define cxt_eapd_info snd_ctl_boolean_mono_info static int cxt_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a47eec5a27b..7e6cc01b521a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -486,15 +486,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, * needed for any "production" models. */ #ifdef CONFIG_SND_DEBUG -static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define alc_gpio_data_info snd_ctl_boolean_mono_info static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -547,15 +539,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, * necessary. */ #ifdef CONFIG_SND_DEBUG -static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 6d2ecc38905c..9838eac9ab59 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -94,15 +94,7 @@ struct si3054_spec { #define PRIVATE_REG(val) ((val>>16)&0xffff) #define PRIVATE_MASK(val) (val&0xffff) -static int si3054_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define si3054_switch_info snd_ctl_boolean_mono_info static int si3054_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3f25de72966b..d2c340e45f9e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1069,14 +1069,7 @@ static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); } -static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define stac92xx_io_switch_info snd_ctl_boolean_mono_info static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { -- cgit v1.2.3 From bddcf5411ffd17bfb86c2baed4a1b859c7071c98 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Jul 2007 18:04:05 +0200 Subject: [ALSA] hda-codec - Fix AD1988 SPDIF output The SPDIF output on AD1988 had some problems due to the wrongly routed analog loopback to SPDIF. This patch fixes the implementation of 'IEC958 Playback Source' mixer to handle the amp bits of mixer widget 0x1d correctly. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 45 ++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index fafadf9fab8e..488724f2e304 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1889,16 +1889,19 @@ static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int sel; - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); - if (sel > 0) { + sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + if (!(sel & 0x80)) + ucontrol->value.enumerated.item[0] = 0; + else { sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0); if (sel < 3) sel++; else sel = 0; + ucontrol->value.enumerated.item[0] = sel; } - ucontrol->value.enumerated.item[0] = sel; return 0; } @@ -1910,17 +1913,32 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.enumerated.item[0]; - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); if (!val) { - change = sel != 0; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x02, 0, - AC_VERB_SET_CONNECT_SEL, 0); + sel = snd_hda_codec_read(codec, 0x1d, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + change = sel & 0x80; + if (change || codec->in_resume) { + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(1)); + } } else { - change = sel == 0; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x02, 0, - AC_VERB_SET_CONNECT_SEL, 1); + sel = snd_hda_codec_read(codec, 0x1d, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT | 0x01); + change = sel & 0x80; + if (change || codec->in_resume) { + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + } sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1; change |= sel != val; @@ -2039,10 +2057,9 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* SPDIF out pin */ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ { } }; -- cgit v1.2.3 From 5b31954e4b364f811450311e3b31d3512e575f63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jul 2007 11:49:22 +0200 Subject: [ALSA] hda-codec - Fix the initial mixer state of ALC262 sony-assamd model Many of ALC262 codes don't call the automute function at the beginning, which may keep the silence until the HP jack is replugged. Now proper init_hook is added. Also, sony-assamd model doesn't handle the widget 0x14 properly, thus calling automute isn't enough. Now Front switch handles both widgets. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 66 +++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 25 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7e6cc01b521a..d839d567f8e4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7140,9 +7140,28 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { { } /* end */ }; +static int alc262_sony_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned long private_save = kcontrol->private_value; + int change; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT); + change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + kcontrol->private_value = private_save; + change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + return change; +} + static struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -7269,20 +7288,17 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec, int force) +static void alc262_hippo_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int mute; + unsigned int present; - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; if (spec->jack_present) { /* mute internal speaker */ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, @@ -7306,24 +7322,19 @@ static void alc262_hippo_unsol_event(struct hda_codec *codec, { if ((res >> 26) != ALC880_HP_EVENT) return; - alc262_hippo_automute(codec, 1); + alc262_hippo_automute(codec); } -static void alc262_hippo1_automute(struct hda_codec *codec, int force) +static void alc262_hippo1_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; unsigned int mute; + unsigned int present; - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } - if (spec->jack_present) { + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { /* mute internal speaker */ snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, 0x80, 0x80); @@ -7346,7 +7357,7 @@ static void alc262_hippo1_unsol_event(struct hda_codec *codec, { if ((res >> 26) != ALC880_HP_EVENT) return; - alc262_hippo1_automute(codec, 1); + alc262_hippo1_automute(codec); } /* @@ -7923,6 +7934,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), @@ -7951,6 +7963,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -7963,6 +7976,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo1_unsol_event, + .init_hook = alc262_hippo1_automute, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -8027,6 +8041,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -8038,6 +8053,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, }; -- cgit v1.2.3 From d01ce99fc53271cd8ef0ef6b9a2790177fd410a1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Jul 2007 16:52:19 +0200 Subject: [ALSA] hda-intel - Coding style fixes Fix codes to follow more to the standard kernel coding style. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.h | 33 +++++--- sound/pci/hda/hda_intel.c | 188 +++++++++++++++++++++++++++++----------------- sound/pci/hda/hda_local.h | 99 ++++++++++++++++-------- sound/pci/hda/hda_proc.c | 27 ++++--- 4 files changed, 225 insertions(+), 122 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 56c26e7ccdf1..6809386109c8 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -199,7 +199,9 @@ enum { #define AC_AMPCAP_OFFSET_SHIFT 0 #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ #define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB in 0.25dB */ +#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB + * in 0.25dB + */ #define AC_AMPCAP_STEP_SIZE_SHIFT 16 #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ #define AC_AMPCAP_MUTE_SHIFT 31 @@ -436,7 +438,8 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; - struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ + /* link caddr -> codec */ + struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; struct mutex cmd_mutex; @@ -499,7 +502,7 @@ struct hda_pcm_ops { /* PCM information for each substream */ struct hda_pcm_stream { - unsigned int substreams; /* number of substreams, 0 = not exist */ + unsigned int substreams; /* number of substreams, 0 = not exist*/ unsigned int channels_min; /* min. number of channels */ unsigned int channels_max; /* max. number of channels */ hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ @@ -582,13 +585,17 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, /* * low level functions */ -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, +unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); -#define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) -int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); +#define snd_hda_param_read(codec, nid, param) \ + snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) +int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *start_id); +int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); struct hda_verb { hda_nid_t nid; @@ -596,7 +603,8 @@ struct hda_verb { u32 param; }; -void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq); +void snd_hda_sequence_write(struct hda_codec *codec, + const struct hda_verb *seq); /* unsolicited event */ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); @@ -610,10 +618,13 @@ int snd_hda_build_controls(struct hda_bus *bus); * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); -void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, +void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int channel_id, int format); -unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, - unsigned int format, unsigned int maxbps); +unsigned int snd_hda_calc_stream_format(unsigned int rate, + unsigned int channels, + unsigned int format, + unsigned int maxbps); int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 92bc8b3fa2a0..ebb442dcc027 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1,6 +1,7 @@ /* * - * hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio. + * hda_intel.c - Implementation of primary alsa driver code base + * for Intel HD Audio. * * Copyright(c) 2004 Intel Corporation. All rights reserved. * @@ -64,11 +65,13 @@ MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); module_param(model, charp, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param(position_fix, int, 0444); -MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); +MODULE_PARM_DESC(position_fix, "Fix DMA pointer " + "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); module_param(probe_mask, int, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param(single_cmd, bool, 0444); -MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); +MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " + "(for debugging only)."); module_param(enable_msi, int, 0); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); @@ -213,15 +216,16 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ #define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE) +#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ + SD_INT_COMPLETE) /* SD_STS */ #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ /* GCTL unsolicited response enable bit */ #define ICH6_GCTL_UREN (1<<8) @@ -257,22 +261,26 @@ enum { */ struct azx_dev { - u32 *bdl; /* virtual address of the BDL */ - dma_addr_t bdl_addr; /* physical address of the BDL */ - u32 *posbuf; /* position buffer pointer */ + u32 *bdl; /* virtual address of the BDL */ + dma_addr_t bdl_addr; /* physical address of the BDL */ + u32 *posbuf; /* position buffer pointer */ - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int fragsize; /* size of each period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ + unsigned int bufsize; /* size of the play buffer in bytes */ + unsigned int fragsize; /* size of each period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ - void __iomem *sd_addr; /* stream descriptor pointer */ + void __iomem *sd_addr; /* stream descriptor pointer */ - u32 sd_int_sta_mask; /* stream int status mask */ + u32 sd_int_sta_mask; /* stream int status mask */ /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, set in PCM open */ - unsigned int format_val; /* format value to be set in the controller and the codec */ + struct snd_pcm_substream *substream; /* assigned substream, + * set in PCM open + */ + unsigned int format_val; /* format value to be set in the + * controller and the codec + */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ /* for sanity check of position buffer */ @@ -418,7 +426,8 @@ static int azx_alloc_cmd_io(struct azx *chip) int err; /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->rb); if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); @@ -531,7 +540,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) azx_update_rirb(chip); spin_unlock_irq(&chip->reg_lock); } - if (! chip->rirb.cmds) + if (!chip->rirb.cmds) return chip->rirb.res; /* the last value */ schedule_timeout(1); } while (time_after_eq(timeout, jiffies)); @@ -585,16 +594,19 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) while (timeout--) { /* check ICB busy bit */ - if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) { + if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { /* Clear IRV valid bit */ - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_VALID); azx_writel(chip, IC, val); - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_BUSY); return 0; } udelay(1); } - snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val); + snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", + azx_readw(chip, IRS), val); return -EIO; } @@ -610,7 +622,8 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) return azx_readl(chip, IR); udelay(1); } - snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); + snd_printd(SFX "get_response timeout: IRS=0x%x\n", + azx_readw(chip, IRS)); return (unsigned int)-1; } @@ -785,7 +798,8 @@ static void azx_init_chip(struct azx *chip) /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio codecs + * Ensuring these bits are 0 clears playback static on some HD Audio + * codecs */ pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); @@ -808,10 +822,13 @@ static void azx_init_chip(struct azx *chip) switch (chip->driver_type) { case AZX_DRIVER_ATI: /* For ATI SB450 azalia HD audio, we need to enable snoop */ - pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + pci_read_config_byte(chip->pci, + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, ®); - pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); + pci_write_config_byte(chip->pci, + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + (reg & 0xf8) | + ATI_SB450_HDAUDIO_ENABLE_SNOOP); break; case AZX_DRIVER_NVIDIA: /* For NVIDIA HDA, enable snoop */ @@ -857,7 +874,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (! chip->single_cmd && (status & RIRB_INT_RESPONSE)) + if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) azx_update_rirb(chip); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -911,9 +928,11 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) int timeout; /* make sure the run bit is zero for SD */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START); + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & + ~SD_CTL_DMA_START); /* reset stream */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET); + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | + SD_CTL_STREAM_RESET); udelay(3); timeout = 300; while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && @@ -931,7 +950,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) /* program the stream_tag */ azx_sd_writel(azx_dev, SD_CTL, - (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) | + (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); /* program the length of samples in cyclic buffer */ @@ -951,11 +970,13 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, + (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE); /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); + azx_sd_writel(azx_dev, SD_CTL, + azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); return 0; } @@ -987,7 +1008,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; - if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0) + err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); + if (err < 0) return err; codecs = audio_codecs = 0; @@ -1038,7 +1060,7 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) nums = chip->capture_streams; } for (i = 0; i < nums; i++, dev++) - if (! chip->azx_dev[dev].opened) { + if (!chip->azx_dev[dev].opened) { chip->azx_dev[dev].opened = 1; return &chip->azx_dev[dev]; } @@ -1052,7 +1074,8 @@ static inline void azx_release_device(struct azx_dev *azx_dev) } static struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | /* No full-resume yet implemented */ @@ -1105,7 +1128,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) 128); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); - if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { + err = hinfo->ops.open(hinfo, apcm->codec, substream); + if (err < 0) { azx_release_device(azx_dev); mutex_unlock(&chip->open_mutex); return err; @@ -1139,9 +1163,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) return 0; } -static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) +static int azx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); } static int azx_pcm_hw_free(struct snd_pcm_substream *substream) @@ -1175,13 +1201,15 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) runtime->channels, runtime->format, hinfo->maxbps); - if (! azx_dev->format_val) { - snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", + if (!azx_dev->format_val) { + snd_printk(KERN_ERR SFX + "invalid format_val, rate=%d, ch=%d, format=%d\n", runtime->rate, runtime->channels, runtime->format); return -EINVAL; } - snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n", + snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, " + "format=0x%x\n", azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); azx_setup_periods(azx_dev); azx_setup_controller(chip, azx_dev); @@ -1223,7 +1251,8 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) cmd == SNDRV_PCM_TRIGGER_SUSPEND || cmd == SNDRV_PCM_TRIGGER_STOP) { int timeout = 5000; - while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) + while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) && + --timeout) ; } return err; @@ -1241,7 +1270,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); if (chip->position_fix == POS_FIX_AUTO && - azx_dev->period_intr == 1 && ! pos) { + azx_dev->period_intr == 1 && !pos) { printk(KERN_WARNING "hda-intel: Invalid position buffer, " "using LPIB read method instead.\n"); @@ -1292,7 +1321,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_assert(cpcm->name, return -EINVAL); err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, - cpcm->stream[0].substreams, cpcm->stream[1].substreams, + cpcm->stream[0].substreams, + cpcm->stream[1].substreams, &pcm); if (err < 0) return err; @@ -1327,7 +1357,8 @@ static int __devinit azx_pcm_create(struct azx *chip) int c, err; int pcm_dev; - if ((err = snd_hda_build_pcms(chip->bus)) < 0) + err = snd_hda_build_pcms(chip->bus); + if (err < 0) return err; /* create audio PCMs */ @@ -1338,10 +1369,12 @@ static int __devinit azx_pcm_create(struct azx *chip) if (codec->pcm_info[c].is_modem) continue; /* create later */ if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { - snd_printk(KERN_ERR SFX "Too many audio PCMs\n"); + snd_printk(KERN_ERR SFX + "Too many audio PCMs\n"); return -EINVAL; } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + err = create_codec_pcm(chip, codec, + &codec->pcm_info[c], pcm_dev); if (err < 0) return err; pcm_dev++; @@ -1353,13 +1386,15 @@ static int __devinit azx_pcm_create(struct azx *chip) list_for_each(p, &chip->bus->codec_list) { codec = list_entry(p, struct hda_codec, list); for (c = 0; c < codec->num_pcms; c++) { - if (! codec->pcm_info[c].is_modem) + if (!codec->pcm_info[c].is_modem) continue; /* already created */ if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); + snd_printk(KERN_ERR SFX + "Too many modem PCMs\n"); return -EINVAL; } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + err = create_codec_pcm(chip, codec, + &codec->pcm_info[c], pcm_dev); if (err < 0) return err; chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; @@ -1386,7 +1421,8 @@ static int __devinit azx_init_stream(struct azx *chip) int i; /* initialize each stream (aka device) - * assign the starting bdl address to each stream (device) and initialize + * assign the starting bdl address to each stream (device) + * and initialize */ for (i = 0; i < chip->num_streams; i++) { unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); @@ -1650,28 +1686,35 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, break; } chip->num_streams = chip->playback_streams + chip->capture_streams; - chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); + chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), + GFP_KERNEL); if (!chip->azx_dev) { snd_printk(KERN_ERR "cannot malloc azx_dev\n"); goto errout; } /* allocate memory for the BDL for each stream */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - BDL_SIZE, &chip->bdl)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + BDL_SIZE, &chip->bdl); + if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - chip->num_streams * 8, &chip->posbuf)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + chip->num_streams * 8, &chip->posbuf); + if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); goto errout; } /* allocate CORB/RIRB */ - if (! chip->single_cmd) - if ((err = azx_alloc_cmd_io(chip)) < 0) + if (!chip->single_cmd) { + err = azx_alloc_cmd_io(chip); + if (err < 0) goto errout; + } /* initialize streams */ azx_init_stream(chip); @@ -1688,14 +1731,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err <0) { snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); goto errout; } strcpy(card->driver, "HDA-Intel"); strcpy(card->shortname, driver_short_names[chip->driver_type]); - sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; @@ -1705,7 +1750,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, return err; } -static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +static int __devinit azx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct azx *chip; @@ -1725,26 +1771,30 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * card->private_data = chip; /* create codec instances */ - if ((err = azx_codec_create(chip, model)) < 0) { + err = azx_codec_create(chip, model); + if (err < 0) { snd_card_free(card); return err; } /* create PCM streams */ - if ((err = azx_pcm_create(chip)) < 0) { + err = azx_pcm_create(chip); + if (err < 0) { snd_card_free(card); return err; } /* create mixer controls */ - if ((err = azx_mixer_create(chip)) < 0) { + err = azx_mixer_create(chip); + if (err < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pci->dev); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index f91ea5ec9f6d..c8d34a5b081f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -26,7 +26,8 @@ /* * for mixer controls */ -#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) +#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ + ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ @@ -64,13 +65,20 @@ #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) -int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); -int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv); +int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); /* lowlevel accessor with caching; use carefully */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); @@ -86,10 +94,13 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } /* stereo switch binding multiple inputs */ -#define HDA_BIND_MUTE(xname,nid,indices,dir) HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) +#define HDA_BIND_MUTE(xname,nid,indices,dir) \ + HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); @@ -107,8 +118,10 @@ struct hda_input_mux { struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; }; -int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo); -int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, +int snd_hda_input_mux_info(const struct hda_input_mux *imux, + struct snd_ctl_elem_info *uinfo); +int snd_hda_input_mux_put(struct hda_codec *codec, + const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); @@ -120,13 +133,19 @@ struct hda_channel_mode { const struct hda_verb *sequence; }; -int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, int num_chmodes); -int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, +int snd_hda_ch_mode_info(struct hda_codec *codec, + struct snd_ctl_elem_info *uinfo, + const struct hda_channel_mode *chmode, + int num_chmodes); +int snd_hda_ch_mode_get(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol, + const struct hda_channel_mode *chmode, + int num_chmodes, int max_channels); -int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, +int snd_hda_ch_mode_put(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol, + const struct hda_channel_mode *chmode, + int num_chmodes, int *max_channelsp); /* @@ -146,20 +165,25 @@ struct hda_multi_out { int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ }; -int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); -int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); +int snd_hda_multi_out_dig_open(struct hda_codec *codec, + struct hda_multi_out *mout); +int snd_hda_multi_out_dig_close(struct hda_codec *codec, + struct hda_multi_out *mout); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, +int snd_hda_multi_out_analog_open(struct hda_codec *codec, + struct hda_multi_out *mout, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, +int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, + struct hda_multi_out *mout, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); +int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, + struct hda_multi_out *mout); /* * generic codec parser @@ -181,7 +205,8 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **modelnames, const struct snd_pci_quirk *pci_list); -int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); +int snd_hda_add_new_ctls(struct hda_codec *codec, + struct snd_kcontrol_new *knew); /* * power management @@ -232,7 +257,9 @@ extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; struct auto_pin_cfg { int line_outs; - hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t line_out_pins[5]; /* sorted in the order of + * Front/Surr/CLFE/Side + */ int speaker_outs; hda_nid_t speaker_pins[5]; int hp_outs; @@ -243,13 +270,19 @@ struct auto_pin_cfg { hda_nid_t dig_in_pin; }; -#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) -#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) -#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) -#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) - -int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, +#define get_defcfg_connect(cfg) \ + ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) \ + ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_location(cfg) \ + ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define get_defcfg_sequence(cfg) \ + (cfg & AC_DEFCFG_SEQUENCE) +#define get_defcfg_device(cfg) \ + ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) + +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, hda_nid_t *ignore_nids); /* amp values */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ac15066fd300..ccd19180e541 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -58,7 +58,8 @@ static void print_amp_caps(struct snd_info_buffer *buffer, snd_iprintf(buffer, "N/A\n"); return; } - snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n", + snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, " + "mute=%x\n", caps & AC_AMPCAP_OFFSET, (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, @@ -76,11 +77,13 @@ static void print_amp_vals(struct snd_info_buffer *buffer, for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); if (stereo) { - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_LEFT | dir | i); snd_iprintf(buffer, "0x%02x ", val); } - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_RIGHT | dir | i); snd_iprintf(buffer, "0x%02x]", val); } @@ -237,7 +240,8 @@ static void print_pin_caps(struct snd_info_buffer *buffer, } -static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void print_codec_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct hda_codec *codec = entry->private_data; char buf[32]; @@ -271,9 +275,11 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe return; } for (i = 0; i < nodes; i++, nid++) { - unsigned int wid_caps = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int wid_caps = + snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = + (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; int conn_len = 0; hda_nid_t conn[HDA_MAX_CONNECTIONS]; @@ -313,7 +319,9 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe if (wid_type == AC_WID_PIN) { unsigned int pinctls; print_pin_caps(buffer, codec, nid); - pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + pinctls = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0); snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); if (pinctls & AC_PINCTL_IN_EN) snd_iprintf(buffer, " IN"); @@ -333,7 +341,8 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe if (wid_caps & AC_WCAP_POWER) snd_iprintf(buffer, " Power: 0x%x\n", snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0)); + AC_VERB_GET_POWER_STATE, + 0)); if (wid_caps & AC_WCAP_CONN_LIST) { int c, curr = -1; -- cgit v1.2.3 From 2807314d467e7dd929c42050031aabbd28e78f0b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Jul 2007 18:58:06 +0200 Subject: [ALSA] hda-intel - Add hwdep interface Added a hwdep interface for each codec (enabled per kconfig). This interface can be used for reading/writing HD-audio verbs and other purposes as future extensions. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/Makefile | 9 ++-- sound/pci/hda/hda_codec.c | 4 ++ sound/pci/hda/hda_codec.h | 3 ++ sound/pci/hda/hda_hwdep.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 5 ++ 5 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 sound/pci/hda/hda_hwdep.c (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index b2484bbdcc1d..f85c34551ac8 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,8 +1,8 @@ -snd-hda-intel-objs := hda_intel.o +snd-hda-intel-y := hda_intel.o # since snd-hda-intel is the only driver using hda-codec, # merge it into a single module although it was originally # designed to be individual modules -snd-hda-intel-objs += hda_codec.o \ +snd-hda-intel-y += hda_codec.o \ hda_generic.o \ patch_realtek.o \ patch_cmedia.o \ @@ -12,8 +12,7 @@ snd-hda-intel-objs += hda_codec.o \ patch_atihdmi.o \ patch_conexant.o \ patch_via.o -ifdef CONFIG_PROC_FS -snd-hda-intel-objs += hda_proc.o -endif +snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o +snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a05db2f214bd..e7843ffeeb2f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -31,6 +31,7 @@ #include #include #include "hda_local.h" +#include /* @@ -594,6 +595,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, init_unsol_queue(bus); snd_hda_codec_proc_new(codec); +#ifdef CONFIG_SND_HDA_HWDEP + snd_hda_create_hwdep(codec); +#endif sprintf(component, "HDA:%08x", codec->vendor_id); snd_component_add(codec->bus->card, component); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 6809386109c8..1370e346bf34 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -24,6 +24,7 @@ #include #include #include +#include /* * nodes @@ -566,6 +567,8 @@ struct hda_codec { unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ + + struct snd_hwdep *hwdep; /* assigned hwdep device */ }; /* direction */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c new file mode 100644 index 000000000000..64be7b533488 --- /dev/null +++ b/sound/pci/hda/hda_hwdep.c @@ -0,0 +1,122 @@ +/* + * HWDEP Interface for HD-audio codec + * + * Copyright (c) 2007 Takashi Iwai + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" +#include + +/* + * write/read an out-of-bound verb + */ +static int verb_write_ioctl(struct hda_codec *codec, + struct hda_verb_ioctl __user *arg) +{ + u32 verb, res; + + if (get_user(verb, &arg->verb)) + return -EFAULT; + res = snd_hda_codec_read(codec, verb >> 24, 0, + (verb >> 8) & 0xffff, verb & 0xff); + if (put_user(res, &arg->res)) + return -EFAULT; + return 0; +} + +static int get_wcap_ioctl(struct hda_codec *codec, + struct hda_verb_ioctl __user *arg) +{ + u32 verb, res; + + if (get_user(verb, &arg->verb)) + return -EFAULT; + res = get_wcaps(codec, verb >> 24); + if (put_user(res, &arg->res)) + return -EFAULT; + return 0; +} + + +/* + */ +static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct hda_codec *codec = hw->private_data; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case HDA_IOCTL_PVERSION: + return put_user(HDA_HWDEP_VERSION, (int __user *)argp); + case HDA_IOCTL_VERB_WRITE: + return verb_write_ioctl(codec, argp); + case HDA_IOCTL_GET_WCAP: + return get_wcap_ioctl(codec, argp); + } + return -ENOIOCTLCMD; +} + +#ifdef CONFIG_COMPAT +static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return hda_hwdep_ioctl(hw, file, cmd, compat_ptr(arg)); +} +#endif + +static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) +{ +#ifndef CONFIG_SND_DEBUG_DETECT + if (!capable(CAP_SYS_RAWIO)) + return -EACCES; +#endif + return 0; +} + +int __devinit snd_hda_create_hwdep(struct hda_codec *codec) +{ + char hwname[16]; + struct snd_hwdep *hwdep; + int err; + + sprintf(hwname, "HDA Codec %d", codec->addr); + err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep); + if (err < 0) + return err; + codec->hwdep = hwdep; + sprintf(hwdep->name, "HDA Codec %d", codec->addr); + hwdep->iface = SNDRV_HWDEP_IFACE_HDA; + hwdep->private_data = codec; + hwdep->exclusive = 1; + + hwdep->ops.open = hda_hwdep_open; + hwdep->ops.ioctl = hda_hwdep_ioctl; +#ifdef CONFIG_COMPAT + hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; +#endif + + return 0; +} diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index c8d34a5b081f..12428a67eb2a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -313,4 +313,9 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); +/* + * hwdep interface + */ +int snd_hda_create_hwdep(struct hda_codec *codec); + #endif /* __SOUND_HDA_LOCAL_H */ -- cgit v1.2.3 From 532d5381793f3c824f8ff68d7067fab8c76bb811 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Jul 2007 19:02:40 +0200 Subject: [ALSA] hda-codec - Add a generic bind-control helper Added callbacks for a generic bind-control of mixer elements. This can be used for creating a mixer element controlling multiple widgets at the same time. Two macros, HDA_BIND_VOL() and HDA_BIND_SW(), are introduced for creating bind-volume and bind-switch, respectively. It taks the mixer element name and struct hda_bind_ctls pointer, which contains the real control callbacks in ops field and long array for private_value of each bound widget. All widgets have to be the same type (i.e. the same amp capability). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 87 +++++++++++++++++++++ sound/pci/hda/hda_local.h | 47 +++++++++++ sound/pci/hda/patch_analog.c | 177 ++++++++++-------------------------------- sound/pci/hda/patch_realtek.c | 28 +++---- 4 files changed, 184 insertions(+), 155 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e7843ffeeb2f..36879a93eac4 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1005,6 +1005,93 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, return err < 0 ? err : change; } +/* + * generic bound volume/swtich controls + */ +int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->info(kcontrol, uinfo); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->get(kcontrol, ucontrol); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + unsigned long *vals; + int err = 0, change = 0; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + for (vals = c->values; *vals; vals++) { + kcontrol->private_value = *vals; + err = c->ops->put(kcontrol, ucontrol); + if (err < 0) + break; + change |= err; + } + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err < 0 ? err : change; +} + +int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +struct hda_ctl_ops snd_hda_bind_vol = { + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = snd_hda_mixer_amp_volume_put, + .tlv = snd_hda_mixer_amp_tlv +}; + +struct hda_ctl_ops snd_hda_bind_sw = { + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = snd_hda_mixer_amp_switch_put, + .tlv = snd_hda_mixer_amp_tlv +}; + /* * SPDIF out controls */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 12428a67eb2a..fafcffe6fc79 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -102,6 +102,53 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +/* more generic bound controls */ +struct hda_ctl_ops { + snd_kcontrol_info_t *info; + snd_kcontrol_get_t *get; + snd_kcontrol_put_t *put; + snd_kcontrol_tlv_rw_t *tlv; +}; + +extern struct hda_ctl_ops snd_hda_bind_vol; /* for bind-volume with TLV */ +extern struct hda_ctl_ops snd_hda_bind_sw; /* for bind-switch */ + +struct hda_bind_ctls { + struct hda_ctl_ops *ops; + long values[]; +}; + +int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv); + +#define HDA_BIND_VOL(xname, bindrec) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ + SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,\ + .info = snd_hda_mixer_bind_ctls_info,\ + .get = snd_hda_mixer_bind_ctls_get,\ + .put = snd_hda_mixer_bind_ctls_put,\ + .tlv = { .c = snd_hda_mixer_bind_tlv },\ + .private_value = (long) (bindrec) } +#define HDA_BIND_SW(xname, bindrec) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ + .name = xname, \ + .info = snd_hda_mixer_bind_ctls_info,\ + .get = snd_hda_mixer_bind_ctls_get,\ + .put = snd_hda_mixer_bind_ctls_put,\ + .private_value = (long) (bindrec) } + +/* + * SPDIF I/O + */ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 488724f2e304..cc2e944cc59f 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -422,94 +422,36 @@ static struct hda_input_mux ad1986a_capture_source = { }, }; -/* - * PCM control - * - * bind volumes/mutes of 3 DACs as a single PCM control for simplicity - */ - -#define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info - -static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} -static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; - - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} - -#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info - -static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; +static struct hda_bind_ctls ad1986a_bind_pcm_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), + 0 + }, +}; - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} +static struct hda_bind_ctls ad1986a_bind_pcm_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* * mixers */ static struct snd_kcontrol_new ad1986a_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, - .info = ad1986a_pcm_amp_vol_info, - .get = ad1986a_pcm_amp_vol_get, - .put = ad1986a_pcm_amp_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = ad1986a_pcm_amp_sw_info, - .get = ad1986a_pcm_amp_sw_get, - .put = ad1986a_pcm_amp_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, + /* + * bind volumes/mutes of 3 DACs as a single PCM control for simplicity + */ + HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), + HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), @@ -596,41 +538,23 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { /* laptop-eapd model - 2ch only */ /* master controls both pins 0x1a and 0x1b */ -static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} - -static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; +static struct hda_bind_ctls ad1986a_laptop_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; - change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - return change; -} +static struct hda_bind_ctls ad1986a_laptop_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { .num_items = 3, @@ -642,23 +566,8 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { }; static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1986a_laptop_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1986a_laptop_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), @@ -856,7 +765,6 @@ static int patch_ad1986a(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 6; @@ -1064,7 +972,6 @@ static int patch_ad1983(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -1466,7 +1373,6 @@ static int patch_ad1981(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -2672,7 +2578,6 @@ static int patch_ad1988(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; if (is_rev2(codec)) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d839d567f8e4..f27e073d22b1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7140,28 +7140,18 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { { } /* end */ }; -static int alc262_sony_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned long private_save = kcontrol->private_value; - int change; - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT); - change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - kcontrol->private_value = private_save; - change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - return change; -} +static struct hda_bind_ctls alc262_sony_bind_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + 0, + }, +}; static struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Front Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc262_sony_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_SW("Front Playback Switch", &alc262_sony_bind_sw), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), -- cgit v1.2.3 From 82467611ffc41fba534c95f8b4ae3887a90f5a66 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Jul 2007 19:15:54 +0200 Subject: [ALSA] hda-codec - kernel config for each codec Create kernel configs to choose the codec support codes to build. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/Makefile | 20 ++++++++++---------- sound/pci/hda/hda_codec.c | 31 +++++++++++++++++++++++++++---- sound/pci/hda/hda_patch.h | 16 ++++++++++++++++ 3 files changed, 53 insertions(+), 14 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index f85c34551ac8..6d43e39b9d0b 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -2,17 +2,17 @@ snd-hda-intel-y := hda_intel.o # since snd-hda-intel is the only driver using hda-codec, # merge it into a single module although it was originally # designed to be individual modules -snd-hda-intel-y += hda_codec.o \ - hda_generic.o \ - patch_realtek.o \ - patch_cmedia.o \ - patch_analog.o \ - patch_sigmatel.o \ - patch_si3054.o \ - patch_atihdmi.o \ - patch_conexant.o \ - patch_via.o +snd-hda-intel-y += hda_codec.o snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_GENERIC) += hda_generic.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 36879a93eac4..c4cf2c7230ef 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -388,6 +388,13 @@ int __devinit snd_hda_bus_new(struct snd_card *card, return 0; } +#ifdef CONFIG_SND_HDA_GENERIC +#define is_generic_config(codec) \ + (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) +#else +#define is_generic_config(codec) 0 +#endif + /* * find a matching codec preset */ @@ -396,7 +403,7 @@ find_codec_preset(struct hda_codec *codec) { const struct hda_codec_preset **tbl, *preset; - if (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) + if (is_generic_config(codec)) return NULL; /* use the generic parser */ for (tbl = hda_preset_tables; *tbl; tbl++) { @@ -582,10 +589,26 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_get_codec_name(codec, bus->card->mixername, sizeof(bus->card->mixername)); - if (codec->preset && codec->preset->patch) - err = codec->preset->patch(codec); - else +#ifdef CONFIG_SND_HDA_GENERIC + if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); + goto patched; + } +#endif + if (codec->preset && codec->preset->patch) { + err = codec->preset->patch(codec); + goto patched; + } + + /* call the default parser */ +#ifdef CONFIG_SND_HDA_GENERIC + err = snd_hda_parse_generic_codec(codec); +#else + printk(KERN_ERR "hda-codec: No codec parser is available\n"); + err = -ENODEV; +#endif + + patched: if (err < 0) { snd_hda_codec_free(codec); return err; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 9f9e9ae44a9d..f5c23bb16d7e 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -20,13 +20,29 @@ extern struct hda_codec_preset snd_hda_preset_conexant[]; extern struct hda_codec_preset snd_hda_preset_via[]; static const struct hda_codec_preset *hda_preset_tables[] = { +#ifdef CONFIG_SND_HDA_CODEC_REALTEK snd_hda_preset_realtek, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CMEDIA snd_hda_preset_cmedia, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ANALOG snd_hda_preset_analog, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL snd_hda_preset_sigmatel, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SI3054 snd_hda_preset_si3054, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI snd_hda_preset_atihdmi, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CONEXANT snd_hda_preset_conexant, +#endif +#ifdef CONFIG_SND_HDA_CODEC_VIA snd_hda_preset_via, +#endif NULL }; -- cgit v1.2.3 From 625dc0bf4d91d379e8b4d5c3c9e05ad6fa978c51 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 30 Jul 2007 21:42:10 +0200 Subject: [ALSA] hda-codec - Add support for the ASRock K8NF6G-VSTA motherboard This patch adds ALC861VD support for the ASRock K8NF6G-VSTA motherboard. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f27e073d22b1..db4aded97456 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10336,6 +10336,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), {} }; -- cgit v1.2.3 From 312d045c75fc76e7de51520c3c1b6b5bec565cc9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jul 2007 11:08:10 +0200 Subject: [ALSA] hda-intel - Fix compile warning in snd_hwdep_ioctl_compat() Fix missing cast: sound/pci/hda/hda_hwdep.c:86: warning: passing argument 4 of 'hda_hwdep_ioctl' makes integer from pointer without a cast Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_hwdep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 64be7b533488..bafb7b01f5a1 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -83,7 +83,7 @@ static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) { - return hda_hwdep_ioctl(hw, file, cmd, compat_ptr(arg)); + return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg)); } #endif -- cgit v1.2.3 From d71a5c50ca9b1e24987df3cdd3a1a4fb06d265e4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jul 2007 11:09:16 +0200 Subject: [ALSA] hda-intel - Fix a typo in Makefile Fixed a typo of CONFIG_SND_HDA_GENERIC. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 6d43e39b9d0b..ab0c726d648e 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -5,7 +5,7 @@ snd-hda-intel-y := hda_intel.o snd-hda-intel-y += hda_codec.o snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_GENERIC) += hda_generic.o +snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o -- cgit v1.2.3 From 8259980ebcecd8096a04cc43c1c1d72e1c0ed165 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jul 2007 15:56:24 +0200 Subject: [ALSA] hda-codec - Fix GPIO in resume Reinitialize GPIO in resume callback if necessary. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d2c340e45f9e..5ca430cc399a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -95,6 +95,8 @@ struct sigmatel_spec { unsigned int hp_detect: 1; unsigned int gpio_mute: 1; + unsigned int gpio_mask, gpio_data; + /* playback */ struct hda_multi_out multiout; hda_nid_t dac_nids[5]; @@ -854,20 +856,20 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) spec->pin_configs[i]); } -static void stac92xx_enable_gpio_mask(struct hda_codec *codec, - int gpio_mask, int gpio_data) +static void stac92xx_enable_gpio_mask(struct hda_codec *codec) { + struct sigmatel_spec *spec = codec->spec; /* Configure GPIOx as output */ snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpio_mask); + AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); /* Configure GPIOx as CMOS */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); /* Assert GPIOx */ snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpio_data); + AC_VERB_SET_GPIO_DATA, spec->gpio_data); /* Enable GPIOx */ snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpio_mask); + AC_VERB_SET_GPIO_MASK, spec->gpio_mask); } /* @@ -1935,8 +1937,10 @@ static int stac92xx_resume(struct hda_codec *codec) struct sigmatel_spec *spec = codec->spec; int i; - stac92xx_init(codec); stac92xx_set_config_regs(codec); + if (spec->gpio_mask && spec->gpio_data) + stac92xx_enable_gpio_mask(codec); + stac92xx_init(codec); snd_hda_resume_ctls(codec, spec->mixer); for (i = 0; i < spec->num_mixers; i++) snd_hda_resume_ctls(codec, spec->mixers[i]); @@ -2240,7 +2244,8 @@ static int patch_stac927x(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; /* GPIO0 High = Enable EAPD */ - stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001); + spec->gpio_mask = spec->gpio_data = 0x00000001; + stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { @@ -2265,7 +2270,7 @@ static int patch_stac927x(struct hda_codec *codec) static int patch_stac9205(struct hda_codec *codec) { struct sigmatel_spec *spec; - int err, gpio_mask, gpio_data; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -2308,15 +2313,16 @@ static int patch_stac9205(struct hda_codec *codec) stac92xx_set_config_reg(codec, 0x1f, 0x01441030); stac92xx_set_config_reg(codec, 0x20, 0x1c410030); - gpio_mask = 0x00000007; /* GPIO0-2 */ + spec->gpio_mask = 0x00000007; /* GPIO0-2 */ /* GPIO0 High = EAPD, GPIO1 Low = DRM, * GPIO2 High = Headphone Mute */ - gpio_data = 0x00000005; + spec->gpio_data = 0x00000005; } else - gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */ + spec->gpio_mask = spec->gpio_data = + 0x00000001; /* GPIO0 High = EAPD */ - stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data); + stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); if (!err) { if (spec->board_config < 0) { -- cgit v1.2.3 From 12f288bffeaa3196ebd5da49c5c7ac06c6188b61 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Aug 2007 15:51:59 +0200 Subject: [ALSA] hda-intel - Remove invalid __devinit Some functions in hda_codec.c are called from patch ops, which are kept in the codec instance even after initialization. Thus they shouldn't be marked as __devinit. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c4cf2c7230ef..fc934baaae65 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1325,8 +1325,7 @@ static struct snd_kcontrol_new dig_mixes[] = { * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t nid) +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; @@ -1424,8 +1423,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = { * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, - hda_nid_t nid) +int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; @@ -1895,9 +1893,9 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) * * If no entries are matching, the function returns a negative value. */ -int __devinit snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char **models, - const struct snd_pci_quirk *tbl) +int snd_hda_check_board_config(struct hda_codec *codec, + int num_configs, const char **models, + const struct snd_pci_quirk *tbl) { if (codec->bus->modelname && models) { int i; @@ -1947,8 +1945,7 @@ int __devinit snd_hda_check_board_config(struct hda_codec *codec, * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_add_new_ctls(struct hda_codec *codec, - struct snd_kcontrol_new *knew) +int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) { int err; @@ -2224,7 +2221,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, * Helper for automatic ping configuration */ -static int __devinit is_in_nid_list(hda_nid_t nid, hda_nid_t *list) +static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) { for (; *list; list++) if (*list == nid) @@ -2275,9 +2272,9 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ -int __devinit snd_hda_parse_pin_def_config(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids) +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + hda_nid_t *ignore_nids) { hda_nid_t nid, nid_start; int nodes; -- cgit v1.2.3 From 4ff076e5d925d8f714b88a1d3992796f89b45450 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Tue, 7 Aug 2007 11:48:12 +0200 Subject: [ALSA] hda-codec - Add more Dell systems This patch adds support for Dell E520 and a couple of other 965 based systems. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 5ca430cc399a..87a36e9d6546 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -80,6 +80,7 @@ enum { STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, + STAC_DELL_3ST, STAC_927X_MODELS }; @@ -719,16 +720,25 @@ static unsigned int d965_5st_pin_configs[14] = { 0x40000100, 0x40000100 }; +static unsigned int dell_3st_pin_configs[14] = { + 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, + 0x01111212, 0x01116211, 0x01813050, 0x01112214, + 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, + 0x40c003fc, 0x40000100 +}; + static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, [STAC_D965_5ST] = d965_5st_pin_configs, + [STAC_DELL_3ST] = dell_3st_pin_configs, }; static const char *stac927x_models[STAC_927X_MODELS] = { [STAC_D965_REF] = "ref", [STAC_D965_3ST] = "3stack", [STAC_D965_5ST] = "5stack", + [STAC_DELL_3ST] = "dell-3stack", }; static struct snd_pci_quirk stac927x_cfg_tbl[] = { @@ -755,6 +765,10 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), + /* Dell 3 stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell E520", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), /* 965 based 5 stack systems */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), -- cgit v1.2.3 From 2880a8670d45f66bbdd3c5dd8f4ba46fe1ce9329 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Tue, 7 Aug 2007 11:50:26 +0200 Subject: [ALSA] hda-codec - Add support for Acer Aspire laptops This patch adds support for some Acer Aspire systems. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index db4aded97456..39c08bb670d1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -167,6 +167,7 @@ enum { ALC883_TARGA_DIG, ALC883_TARGA_2ch_DIG, ALC883_ACER, + ALC883_ACER_ASPIRE, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -6219,6 +6220,33 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, + { } /* end */ +}; + static struct snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -6436,6 +6464,18 @@ static struct hda_verb alc883_medion_md2_verbs[] = { { } /* end */ }; +static struct hda_verb alc883_acer_aspire_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + /* toggle speaker-output according to the hp-jack state */ static void alc883_medion_md2_automute(struct hda_codec *codec) { @@ -6622,6 +6662,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_TARGA_DIG] = "targa-dig", [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_ACER] = "acer", + [ALC883_ACER_ASPIRE] = "acer-aspire", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -6657,6 +6698,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), @@ -6771,6 +6813,20 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, }, + [ALC883_ACER_ASPIRE] = { + .mixers = { alc883_acer_aspire_mixer}, + .init_verbs = { alc883_init_verbs, alc883_acer_aspire_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_medion_md2_unsol_event, + .init_hook = alc883_medion_md2_automute, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, -- cgit v1.2.3 From 01751f54ff23b9d59e07f9c9ef189d4733525463 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2007 16:59:39 +0200 Subject: [ALSA] hda-codec - rewrite amp cache more generic Rewrite the code to handle amp cache and hash tables to be more generic. This routine will be used by the register caches in the next patch. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 89 +++++++++++++++++++++++++++-------------------- sound/pci/hda/hda_codec.h | 24 ++++++++----- 2 files changed, 68 insertions(+), 45 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index fc934baaae65..46f8ab1df874 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -494,6 +494,10 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) } +static void init_hda_cache(struct hda_cache_rec *cache, + unsigned int record_size); +static inline void free_hda_cache(struct hda_cache_rec *cache); + /* * codec destructor */ @@ -505,13 +509,11 @@ static void snd_hda_codec_free(struct hda_codec *codec) codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); - kfree(codec->amp_info); + free_hda_cache(&codec->amp_cache); kfree(codec->wcaps); kfree(codec); } -static void init_amp_hash(struct hda_codec *codec); - /** * snd_hda_codec_new - create a HDA codec * @bus: the bus to assign @@ -545,7 +547,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, codec->bus = bus; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); - init_amp_hash(codec); + init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -664,59 +666,72 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void __devinit init_amp_hash(struct hda_codec *codec) +static void __devinit init_hda_cache(struct hda_cache_rec *cache, + unsigned int record_size) +{ + memset(cache, 0, sizeof(*cache)); + memset(cache->hash, 0xff, sizeof(cache->hash)); + cache->record_size = record_size; +} + +static inline void free_hda_cache(struct hda_cache_rec *cache) { - memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); - codec->num_amp_entries = 0; - codec->amp_info_size = 0; - codec->amp_info = NULL; + kfree(cache->buffer); } /* query the hash. allocate an entry if not found. */ -static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) +static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, + u32 key) { - u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); - u16 cur = codec->amp_hash[idx]; - struct hda_amp_info *info; + u16 idx = key % (u16)ARRAY_SIZE(cache->hash); + u16 cur = cache->hash[idx]; + struct hda_cache_head *info; while (cur != 0xffff) { - info = &codec->amp_info[cur]; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ - if (codec->num_amp_entries >= codec->amp_info_size) { + if (cache->num_entries >= cache->size) { /* reallocate the array */ - int new_size = codec->amp_info_size + 64; - struct hda_amp_info *new_info; - new_info = kcalloc(new_size, sizeof(struct hda_amp_info), - GFP_KERNEL); - if (!new_info) { + unsigned int new_size = cache->size + 64; + void *new_buffer; + new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); + if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } - if (codec->amp_info) { - memcpy(new_info, codec->amp_info, - codec->amp_info_size * - sizeof(struct hda_amp_info)); - kfree(codec->amp_info); + if (cache->buffer) { + memcpy(new_buffer, cache->buffer, + cache->size * cache->record_size); + kfree(cache->buffer); } - codec->amp_info_size = new_size; - codec->amp_info = new_info; + cache->size = new_size; + cache->buffer = new_buffer; } - cur = codec->num_amp_entries++; - info = &codec->amp_info[cur]; + cur = cache->num_entries++; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); info->key = key; - info->status = 0; /* not initialized yet */ - info->next = codec->amp_hash[idx]; - codec->amp_hash[idx] = cur; + info->val = 0; + info->next = cache->hash[idx]; + cache->hash[idx] = cur; return info; } +/* query and allocate an amp hash entry */ +static inline struct hda_amp_info * +get_alloc_amp_hash(struct hda_codec *codec, u32 key) +{ + return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); +} + /* * query AMP capabilities for the given widget and direction */ @@ -727,7 +742,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); if (!info) return 0; - if (!(info->status & INFO_AMP_CAPS)) { + if (!(info->head.val & INFO_AMP_CAPS)) { if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) nid = codec->afg; info->amp_caps = snd_hda_param_read(codec, nid, @@ -735,7 +750,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); if (info->amp_caps) - info->status |= INFO_AMP_CAPS; + info->head.val |= INFO_AMP_CAPS; } return info->amp_caps; } @@ -749,7 +764,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, if (!info) return -EINVAL; info->amp_caps = caps; - info->status |= INFO_AMP_CAPS; + info->head.val |= INFO_AMP_CAPS; return 0; } @@ -763,7 +778,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec, { u32 val, parm; - if (info->status & INFO_AMP_VOL(ch)) + if (info->head.val & INFO_AMP_VOL(ch)) return info->vol[ch]; parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; @@ -772,7 +787,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec, val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); info->vol[ch] = val & 0xff; - info->status |= INFO_AMP_VOL(ch); + info->head.val |= INFO_AMP_VOL(ch); return info->vol[ch]; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1370e346bf34..1a69743160ce 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -480,12 +480,24 @@ struct hda_codec_ops { }; /* record for amp information cache */ -struct hda_amp_info { +struct hda_cache_head { u32 key; /* hash key */ + u16 val; /* assigned value */ + u16 next; /* next link; -1 = terminal */ +}; + +struct hda_amp_info { + struct hda_cache_head head; u32 amp_caps; /* amp capabilities */ u16 vol[2]; /* current volume & mute */ - u16 status; /* update flag */ - u16 next; /* next link */ +}; + +struct hda_cache_rec { + u16 hash[64]; /* hash table for index */ + unsigned int num_entries; /* number of assigned entries */ + unsigned int size; /* allocated size */ + unsigned int record_size; /* record size (including header) */ + void *buffer; /* hash table entries */ }; /* PCM callbacks */ @@ -557,11 +569,7 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; - /* hash for amp access */ - u16 amp_hash[32]; - int num_amp_entries; - int amp_info_size; - struct hda_amp_info *amp_info; + struct hda_cache_rec amp_cache; /* cache for amp access */ struct mutex spdif_mutex; unsigned int spdif_status; /* IEC958 status bits */ -- cgit v1.2.3 From b3ac56364126f78cae94eb2a75b72d9ea85aca9d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2007 17:03:40 +0200 Subject: [ALSA] hda-codec - introduce command register cache This patch adds the cache for codec command registers. snd_hda_codec_write_cache() and snd_hda_sequence_write_cache() do the write operations with caching, which values can be resumed via snd_hda_codec_resume_cache(). The patch introduces only the framework, and no codec code is using this cache yet. It'll be implemented in the following patch. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.h | 8 +++++ sound/pci/hda/hda_local.h | 1 + 3 files changed, 100 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 46f8ab1df874..6652a531980d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -510,6 +510,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) if (codec->patch_ops.free) codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); kfree(codec->wcaps); kfree(codec); } @@ -548,6 +549,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -840,6 +842,29 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 1; } +/* resume the all amp commands from the cache */ +void snd_hda_codec_resume_amp(struct hda_codec *codec) +{ + struct hda_amp_info *buffer = codec->amp_cache.buffer; + int i; + + for (i = 0; i < codec->amp_cache.size; i++, buffer++) { + u32 key = buffer->head.key; + hda_nid_t nid; + unsigned int idx, dir, ch; + if (!key) + continue; + nid = key & 0xff; + idx = (key >> 16) & 0xff; + dir = (key >> 24) & 0xff; + for (ch = 0; ch < 2; ch++) { + if (!(buffer->head.val & INFO_AMP_VOL(ch))) + continue; + put_vol_mute(codec, buffer, nid, ch, dir, idx, + buffer->vol[ch]); + } + } +} /* * AMP control callbacks @@ -1458,6 +1483,72 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) } +/* build a 32bit cache key with the widget id and the command parameter */ +#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) +#define get_cmd_cache_nid(key) ((key) & 0xff) +#define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) + +/** + * snd_hda_codec_write_cache - send a single command with caching + * @codec: the HDA codec + * @nid: NID to send the command + * @direct: direct flag + * @verb: the verb to send + * @parm: the parameter for the verb + * + * Send a single command without waiting for response. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) +{ + int err; + mutex_lock(&codec->bus->cmd_mutex); + err = codec->bus->ops.command(codec, nid, direct, verb, parm); + if (!err) { + struct hda_cache_head *c; + u32 key = build_cmd_cache_key(nid, verb); + c = get_alloc_hash(&codec->cmd_cache, key); + if (c) + c->val = parm; + } + mutex_unlock(&codec->bus->cmd_mutex); + return err; +} + +/* resume the all commands from the cache */ +void snd_hda_codec_resume_cache(struct hda_codec *codec) +{ + struct hda_cache_head *buffer = codec->cmd_cache.buffer; + int i; + + for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { + u32 key = buffer->key; + if (!key) + continue; + snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, + get_cmd_cache_cmd(key), buffer->val); + } +} + +/** + * snd_hda_sequence_write_cache - sequence writes with caching + * @codec: the HDA codec + * @seq: VERB array to send + * + * Send the commands sequentially from the given array. + * Thte commands are recorded on cache for power-save and resume. + * The array must be terminated with NID=0. + */ +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq) +{ + for (; seq->nid; seq++) + snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, + seq->param); +} + /* * set power state of the codec */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1a69743160ce..ef94c9122c6d 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -570,6 +570,7 @@ struct hda_codec { u32 *wcaps; struct hda_cache_rec amp_cache; /* cache for amp access */ + struct hda_cache_rec cmd_cache; /* cache for other commands */ struct mutex spdif_mutex; unsigned int spdif_status; /* IEC958 status bits */ @@ -620,6 +621,13 @@ void snd_hda_sequence_write(struct hda_codec *codec, /* unsolicited event */ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); +/* cached write */ +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq); +void snd_hda_codec_resume_cache(struct hda_codec *codec); + /* * Mixer */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index fafcffe6fc79..51208974c2da 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -84,6 +84,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); +void snd_hda_codec_resume_amp(struct hda_codec *codec); /* mono switch binding multiple inputs */ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ -- cgit v1.2.3 From 82beb8fd365afe3891b277c46425083f13e23c56 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2007 17:09:26 +0200 Subject: [ALSA] hda-codec - optimize resume using caches So far, the driver looked the table of snd_kcontrol_new used for creating mixer elements and forces to call each of its put callbacks in PM resume code. This is too ugly and hackish. Now, the resume is simplified using the codec amp and command register caches. The driver simply restores the values that have been written in the cache table. With this simplification, most codec support codes don't require any special resume callback. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 115 +++++++++------------------- sound/pci/hda/hda_codec.h | 10 +-- sound/pci/hda/hda_generic.c | 24 +++--- sound/pci/hda/hda_local.h | 11 +-- sound/pci/hda/patch_analog.c | 68 ++++++----------- sound/pci/hda/patch_atihdmi.c | 16 ---- sound/pci/hda/patch_cmedia.c | 24 ------ sound/pci/hda/patch_conexant.c | 28 +------ sound/pci/hda/patch_realtek.c | 167 +++++++++++++++++++++-------------------- sound/pci/hda/patch_si3054.c | 10 +-- sound/pci/hda/patch_sigmatel.c | 46 +++++------- sound/pci/hda/patch_via.c | 24 ------ 12 files changed, 195 insertions(+), 348 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6652a531980d..1d31da47bc9b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -836,12 +836,13 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; val &= mask; val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; - if (info->vol[ch] == val && !codec->in_resume) + if (info->vol[ch] == val) return 0; put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } +#ifdef CONFIG_PM /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { @@ -865,6 +866,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } +#endif /* CONFIG_PM */ /* * AMP control callbacks @@ -1272,11 +1274,13 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, change = codec->spdif_ctls != val; codec->spdif_ctls = val; - if (change || codec->in_resume) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, - val >> 8); + if (change) { + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + val & 0xff); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, + val >> 8); } mutex_unlock(&codec->spdif_mutex); @@ -1307,17 +1311,19 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0]) val |= AC_DIG1_ENABLE; change = codec->spdif_ctls != val; - if (change || codec->in_resume) { + if (change) { codec->spdif_ctls = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + val & 0xff); /* unmute amp switch (if any) */ if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && - (val & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | - AC_AMP_SET_OUTPUT); + (val & AC_DIG1_ENABLE)) { + snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, + 0x80, 0x00); + snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, + 0x80, 0x00); + } } mutex_unlock(&codec->spdif_mutex); return change; @@ -1409,10 +1415,10 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, mutex_lock(&codec->spdif_mutex); change = codec->spdif_in_enable != val; - if (change || codec->in_resume) { + if (change) { codec->spdif_in_enable = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, val); } mutex_unlock(&codec->spdif_mutex); return change; @@ -1482,6 +1488,10 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) return 0; } +#ifdef CONFIG_PM +/* + * command cache + */ /* build a 32bit cache key with the widget id and the command parameter */ #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) @@ -1548,6 +1558,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } +#endif /* CONFIG_PM */ /* * set power state of the codec @@ -2122,12 +2133,12 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, mode = ucontrol->value.enumerated.item[0]; snd_assert(mode < num_chmodes, return -EINVAL); - if (*max_channelsp == chmode[mode].channels && !codec->in_resume) + if (*max_channelsp == chmode[mode].channels) return 0; /* change the current channel setting */ *max_channelsp = chmode[mode].channels; if (chmode[mode].sequence) - snd_hda_sequence_write(codec, chmode[mode].sequence); + snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } @@ -2160,10 +2171,10 @@ int snd_hda_input_mux_put(struct hda_codec *codec, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, + imux->items[idx].index); *cur_val = idx; return 1; } @@ -2608,65 +2619,13 @@ int snd_hda_resume(struct hda_bus *bus) AC_PWRST_D0); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); - } - return 0; -} - -/** - * snd_hda_resume_ctls - resume controls in the new control list - * @codec: the HDA codec - * @knew: the array of struct snd_kcontrol_new - * - * This function resumes the mixer controls in the struct snd_kcontrol_new array, - * originally for snd_hda_add_new_ctls(). - * The array must be terminated with an empty entry as terminator. - */ -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) -{ - struct snd_ctl_elem_value *val; - - val = kmalloc(sizeof(*val), GFP_KERNEL); - if (!val) - return -ENOMEM; - codec->in_resume = 1; - for (; knew->name; knew++) { - int i, count; - count = knew->count ? knew->count : 1; - for (i = 0; i < count; i++) { - memset(val, 0, sizeof(*val)); - val->id.iface = knew->iface; - val->id.device = knew->device; - val->id.subdevice = knew->subdevice; - strcpy(val->id.name, knew->name); - val->id.index = knew->index ? knew->index : i; - /* Assume that get callback reads only from cache, - * not accessing to the real hardware - */ - if (snd_ctl_elem_read(codec->bus->card, val) < 0) - continue; - snd_ctl_elem_write(codec->bus->card, NULL, val); + else { + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); } } - codec->in_resume = 0; - kfree(val); return 0; } -/** - * snd_hda_resume_spdif_out - resume the digital out - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_out(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_mixes); -} - -/** - * snd_hda_resume_spdif_in - resume the digital in - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_in(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_in_ctls); -} #endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ef94c9122c6d..92938d2a52e2 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -552,11 +552,6 @@ struct hda_codec { /* set by patch */ struct hda_codec_ops patch_ops; - /* resume phase - all controls should update even if - * the values are not changed - */ - unsigned int in_resume; - /* PCM to create, set by patch_ops.build_pcms callback */ unsigned int num_pcms; struct hda_pcm *pcm_info; @@ -622,11 +617,16 @@ void snd_hda_sequence_write(struct hda_codec *codec, int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); /* cached write */ +#ifdef CONFIG_PM int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, const struct hda_verb *seq); void snd_hda_codec_resume_cache(struct hda_codec *codec); +#else +#define snd_hda_codec_write_cache snd_hda_codec_write +#define snd_hda_sequence_write_cache snd_hda_sequence_write +#endif /* * Mixer diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 000287f7da43..d5f1180115ce 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -218,9 +218,9 @@ static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_OUTPUT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 0, 0xff, val); + snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 1, 0xff, val); + return 0; } /* @@ -234,11 +234,11 @@ static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigne ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_INPUT; - // awk added - fixed to allow unmuting of indexed amps - val |= index << AC_AMP_SET_INDEX_SHIFT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_update(codec, node->nid, 0, HDA_INPUT, index, + 0xff, val); + snd_hda_codec_amp_update(codec, node->nid, 1, HDA_INPUT, index, + 0xff, val); + return 0; } /* @@ -248,7 +248,8 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no unsigned int index) { snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); + return snd_hda_codec_write_cache(codec, node->nid, 0, + AC_VERB_SET_CONNECT_SEL, index); } /* @@ -379,7 +380,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, /* unmute the PIN output */ unmute_output(codec, node); /* set PIN-Out enable */ - snd_hda_codec_write(codec, node->nid, 0, + snd_hda_codec_write_cache(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN | ((node->pin_caps & AC_PINCAP_HP_DRV) ? @@ -570,7 +571,8 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, /* unmute the PIN external input */ unmute_input(codec, node, 0); /* index = 0? */ /* set PIN-In enable */ - snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + snd_hda_codec_write_cache(codec, node->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); return 1; /* found */ } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 51208974c2da..8dec32cfdf54 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -84,7 +84,9 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); +#ifdef CONFIG_PM void snd_hda_codec_resume_amp(struct hda_codec *codec); +#endif /* mono switch binding multiple inputs */ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ @@ -256,15 +258,6 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); -/* - * power management - */ -#ifdef CONFIG_PM -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); -int snd_hda_resume_spdif_out(struct hda_codec *codec); -int snd_hda_resume_spdif_in(struct hda_codec *codec); -#endif - /* * unsolicited event handler */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index cc2e944cc59f..f20ddd85db22 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -318,31 +318,11 @@ static void ad198x_free(struct hda_codec *codec) kfree(codec->spec); } -#ifdef CONFIG_PM -static int ad198x_resume(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - static struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, .init = ad198x_init, .free = ad198x_free, -#ifdef CONFIG_PM - .resume = ad198x_resume, -#endif }; @@ -376,12 +356,12 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; - if (eapd == spec->cur_eapd && ! codec->in_resume) + if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); + snd_hda_codec_write_cache(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); return 1; } @@ -882,8 +862,9 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { spec->spdif_route = ucontrol->value.enumerated.item[0]; - snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, - AC_VERB_SET_CONNECT_SEL, spec->spdif_route); + snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, + AC_VERB_SET_CONNECT_SEL, + spec->spdif_route); return 1; } return 0; @@ -1824,33 +1805,34 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_INPUT); change = sel & 0x80; - if (change || codec->in_resume) { - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(1)); + if (change) { + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(1)); } } else { sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_INPUT | 0x01); change = sel & 0x80; - if (change || codec->in_resume) { - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); + if (change) { + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); } sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1; change |= sel != val; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x0b, 0, - AC_VERB_SET_CONNECT_SEL, val - 1); + if (change) + snd_hda_codec_write_cache(codec, 0x0b, 0, + AC_VERB_SET_CONNECT_SEL, + val - 1); } return change; } diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 72d3ab9751ac..fbb8969dc559 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int atihdmi_resume(struct hda_codec *codec) -{ - atihdmi_init(codec); - snd_hda_resume_spdif_out(codec); - - return 0; -} -#endif - /* * Digital out */ @@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patch_ops = { .build_pcms = atihdmi_build_pcms, .init = atihdmi_init, .free = atihdmi_free, -#ifdef CONFIG_PM - .resume = atihdmi_resume, -#endif }; static int patch_atihdmi(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 3c722e667bc8..2468f3171222 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int cmi9880_resume(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - cmi9880_init(codec); - snd_hda_resume_ctls(codec, cmi9880_basic_mixer); - if (spec->channel_modes) - snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - /* * Analog playback callbacks */ @@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patch_ops = { .build_pcms = cmi9880_build_pcms, .init = cmi9880_init, .free = cmi9880_free, -#ifdef CONFIG_PM - .resume = cmi9880_resume, -#endif }; static int patch_cmi9880(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 26034315197f..f1b6d0eda140 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -311,23 +311,6 @@ static void conexant_free(struct hda_codec *codec) kfree(codec->spec); } -#ifdef CONFIG_PM -static int conexant_resume(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - static int conexant_build_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_patch_ops = { .build_pcms = conexant_build_pcms, .init = conexant_init, .free = conexant_free, -#ifdef CONFIG_PM - .resume = conexant_resume, -#endif }; /* @@ -396,13 +376,13 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; - if (eapd == spec->cur_eapd && !codec->in_resume) + if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); + snd_hda_codec_write_cache(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); return 1; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 39c08bb670d1..63011133e3fb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -442,8 +442,9 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, change = pinctl != alc_pin_mode_values[val]; if (change) { /* Set pin mode to that requested */ - snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); /* Also enable the retasking pin's input/output as required * for the requested pin mode. Enum values of 2 or less are @@ -456,19 +457,23 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, * this turns out to be necessary in the future. */ if (val <= 2) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); + snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0, + 0x80, 0x00); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0, + 0x80, 0x00); } else { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0, + 0x80, 0x80); + snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, + 0x80, 0x00); + snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, + 0x80, 0x00); } } return change; @@ -520,7 +525,8 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, gpio_data &= ~mask; else gpio_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); return change; } @@ -573,8 +579,8 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, ctrl_data &= ~mask; else ctrl_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); return change; } @@ -2026,27 +2032,6 @@ static void alc_unsol_event(struct hda_codec *codec, unsigned int res) spec->unsol_event(codec, res); } -#ifdef CONFIG_PM -/* - * resume - */ -static int alc_resume(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - alc_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - /* * Analog playback callbacks */ @@ -2278,9 +2263,6 @@ static struct hda_codec_ops alc_patch_ops = { .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, -#ifdef CONFIG_PM - .resume = alc_resume, -#endif }; @@ -2377,11 +2359,15 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); new_ctl = ctls[ucontrol->value.enumerated.item[0]]; if (old_ctl != new_ctl) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - (ucontrol->value.enumerated.item[0] >= 3 ? - 0xb080 : 0xb000)); + int val; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_ctl); + val = ucontrol->value.enumerated.item[0] >= 3 ? 0x80 : 0x00; + snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, + 0x80, val); + snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, + 0x80, val); return 1; } return 0; @@ -2424,7 +2410,8 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; if (ucontrol->value.enumerated.item[0] != sel) { sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, sel); return 1; } return 0; @@ -4054,13 +4041,17 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; if (present) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 1); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_HP); } else { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); } } @@ -4797,12 +4788,16 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0x00 : 0x80; + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, + imux->items[i].index, + 0x80, v); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, + imux->items[i].index, + 0x80, v); } *cur_val = idx; return 1; @@ -5187,7 +5182,8 @@ static void alc882_targa_automute(struct hda_codec *codec) 0x80, present ? 0x80 : 0); snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, 0x80, present ? 0x80 : 0); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -5777,12 +5773,16 @@ static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0x00 : 0x80; + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, + imux->items[i].index, + 0x80, v); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, + imux->items[i].index, + 0x80, v); } *cur_val = idx; return 1; @@ -6509,8 +6509,8 @@ static void alc883_tagra_automute(struct hda_codec *codec) 0x80, bits); snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - present ? 1 : 3); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) @@ -7510,8 +7510,8 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, 0x80, valp[0] ? 0 : 0x80); change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, 0x80, valp[1] ? 0 : 0x80); - if (change || codec->in_resume) - alc262_fujitsu_automute(codec, codec->in_resume); + if (change) + alc262_fujitsu_automute(codec, 0); return change; } @@ -8328,14 +8328,17 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - idx ); + unsigned int v = (i == idx) ? 0x00 : 0x80; + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, + imux->items[i].index, 0x80, v); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, + imux->items[i].index, 0x80, v); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx ); } *cur_val = idx; return 1; @@ -9916,12 +9919,14 @@ static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0x00 : 0x80; + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, + imux->items[i].index, 0x80, v); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, + imux->items[i].index, 0x80, v); } *cur_val = idx; return 1; @@ -10847,12 +10852,14 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0x00 : 0x80; + snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, + imux->items[i].index, 0x80, v); + snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, + imux->items[i].index, 0x80, v); } *cur_val = idx; return 1; diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 9838eac9ab59..2a4b9609aa5c 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -78,6 +78,8 @@ /* si3054 codec registers (nodes) access macros */ #define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) #define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) +#define SET_REG_CACHE(codec,reg,val) \ + snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val) struct si3054_spec { @@ -113,9 +115,9 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, u16 reg = PRIVATE_REG(kcontrol->private_value); u16 mask = PRIVATE_MASK(kcontrol->private_value); if (uvalue->value.integer.value[0]) - SET_REG(codec, reg, (GET_REG(codec, reg)) | mask); + SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask); else - SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask); + SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask); return 0; } @@ -267,10 +269,6 @@ static struct hda_codec_ops si3054_patch_ops = { .build_pcms = si3054_build_pcms, .init = si3054_init, .free = si3054_free, -#ifdef CONFIG_PM - //.suspend = si3054_suspend, - .resume = si3054_init, -#endif }; static int patch_si3054(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 87a36e9d6546..145a5f3c0632 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -874,16 +874,16 @@ static void stac92xx_enable_gpio_mask(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; /* Configure GPIOx as output */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); /* Configure GPIOx as CMOS */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); + snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); /* Assert GPIOx */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, spec->gpio_data); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, spec->gpio_data); /* Enable GPIOx */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, spec->gpio_mask); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, spec->gpio_mask); } /* @@ -1082,7 +1082,8 @@ static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); } #define stac92xx_io_switch_info snd_ctl_boolean_mono_info @@ -1291,8 +1292,8 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, spec->multiout.num_dacs++; if (conn_len > 1) { /* select this DAC in the pin's input mux */ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, j); } } @@ -1545,9 +1546,9 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const * NID lists. Hopefully this won't get confused. */ for (i = 0; i < spec->num_muxes; i++) { - snd_hda_codec_write(codec, spec->mux_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); + snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); } } @@ -1879,7 +1880,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl | flag); } @@ -1889,7 +1890,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, { unsigned int pin_ctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl & ~flag); } @@ -1948,21 +1949,10 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) #ifdef CONFIG_PM static int stac92xx_resume(struct hda_codec *codec) { - struct sigmatel_spec *spec = codec->spec; - int i; - stac92xx_set_config_regs(codec); - if (spec->gpio_mask && spec->gpio_data) - stac92xx_enable_gpio_mask(codec); stac92xx_init(codec); - snd_hda_resume_ctls(codec, spec->mixer); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); return 0; } #endif diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ba32d1e52cb8..6c734f07e5b5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -543,27 +543,6 @@ static int via_init(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int via_resume(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - via_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - /* */ static struct hda_codec_ops via_patch_ops = { @@ -571,9 +550,6 @@ static struct hda_codec_ops via_patch_ops = { .build_pcms = via_build_pcms, .init = via_init, .free = via_free, -#ifdef CONFIG_PM - .resume = via_resume, -#endif }; /* fill in the dac_nids table from the parsed pin configuration */ -- cgit v1.2.3 From 47fd830acf0b6b5bc75db55d0f2cc64f59a23b5f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2007 17:11:07 +0200 Subject: [ALSA] hda-codec - add snd_hda_codec_stereo() function Added snd_hda_codec_amp_stereo() function that changes both of stereo channels with the same mask and value bits. It simplifies most of amp-handling codes. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 38 +++-- sound/pci/hda/hda_generic.c | 8 +- sound/pci/hda/hda_local.h | 7 + sound/pci/hda/patch_analog.c | 21 ++- sound/pci/hda/patch_conexant.c | 66 ++++----- sound/pci/hda/patch_realtek.c | 325 +++++++++++++++-------------------------- sound/pci/hda/patch_sigmatel.c | 18 ++- 7 files changed, 205 insertions(+), 278 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1d31da47bc9b..043529308676 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -842,6 +842,19 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 1; } +/* + * update the AMP stereo with the same mask and value + */ +int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, + int direction, int idx, int mask, int val) +{ + int ch, ret = 0; + for (ch = 0; ch < 2; ch++) + ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, + idx, mask, val); + return ret; +} + #ifdef CONFIG_PM /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) @@ -913,9 +926,11 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; if (chs & 1) - *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; + *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) + & HDA_AMP_VOLMASK; if (chs & 2) - *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; + *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) + & HDA_AMP_VOLMASK; return 0; } @@ -992,10 +1007,10 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, if (chs & 1) *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & - 0x80) ? 0 : 1; + HDA_AMP_MUTE) ? 0 : 1; if (chs & 2) *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & - 0x80) ? 0 : 1; + HDA_AMP_MUTE) ? 0 : 1; return 0; } @@ -1012,12 +1027,14 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - 0x80, *valp ? 0 : 0x80); + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE); valp++; } if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - 0x80, *valp ? 0 : 0x80); + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE); return change; } @@ -1318,12 +1335,9 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, val & 0xff); /* unmute amp switch (if any) */ if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && - (val & AC_DIG1_ENABLE)) { - snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, - 0x80, 0x00); - snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, - 0x80, 0x00); - } + (val & AC_DIG1_ENABLE)) + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); } mutex_unlock(&codec->spdif_mutex); return change; diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index d5f1180115ce..91cd9b9ea5d1 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -218,8 +218,7 @@ static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 0, 0xff, val); - snd_hda_codec_amp_update(codec, node->nid, 0, HDA_OUTPUT, 1, 0xff, val); + snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); return 0; } @@ -234,10 +233,7 @@ static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigne ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - snd_hda_codec_amp_update(codec, node->nid, 0, HDA_INPUT, index, - 0xff, val); - snd_hda_codec_amp_update(codec, node->nid, 1, HDA_INPUT, index, - 0xff, val); + snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); return 0; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8dec32cfdf54..35ea0cf37a27 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -84,10 +84,17 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); +int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val); #ifdef CONFIG_PM void snd_hda_codec_resume_amp(struct hda_codec *codec); #endif +/* amp value bits */ +#define HDA_AMP_MUTE 0x80 +#define HDA_AMP_UNMUTE 0x00 +#define HDA_AMP_VOLMASK 0x7f + /* mono switch binding multiple inputs */ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index f20ddd85db22..febc2053f08e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1120,10 +1120,9 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 0; /* toggle HP mute appropriately */ - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); + snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + spec->cur_eapd ? 0 : HDA_AMP_MUTE); return 1; } @@ -1136,13 +1135,13 @@ static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); return change; } @@ -1153,10 +1152,8 @@ static void ad1981_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x06, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* toggle input of built-in and mic jack appropriately */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index f1b6d0eda140..ebf83275756e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -472,13 +472,13 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, /* toggle internal speakers mute depending of presence of * the headphone jack */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); return 1; } @@ -491,13 +491,13 @@ static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); return change; } @@ -534,9 +534,9 @@ static void cxt5045_hp_automute(struct hda_codec *codec) spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* unsolicited event for HP jack sensing */ @@ -887,12 +887,12 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, /* toggle internal speakers mute depending of presence of * the headphone jack */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); return 1; } @@ -905,13 +905,13 @@ static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); return change; } @@ -924,12 +924,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* mute internal speaker if HP is plugged */ @@ -941,12 +941,12 @@ static void cxt5047_hp2_automute(struct hda_codec *codec) spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = spec->hp_present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->hp_present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* toggle input of built-in and mic jack appropriately */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 63011133e3fb..29119fd4017d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -457,23 +457,15 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, * this turns out to be necessary in the future. */ if (val <= 2) { - snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0, - 0x80, 0x00); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0, - 0x80, 0x00); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); } else { - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, - 0x80, 0x00); - snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, - 0x80, 0x00); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); } } return change; @@ -1559,15 +1551,11 @@ static void alc880_uniwill_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* auto-toggle front mic */ @@ -1578,11 +1566,8 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } static void alc880_uniwill_automute(struct hda_codec *codec) @@ -1614,11 +1599,8 @@ static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -1626,19 +1608,14 @@ static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) unsigned int present; present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; - - snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, present); - - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, present); - + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); + snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); } + static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -1891,11 +1868,9 @@ static void alc880_lg_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1990,11 +1965,9 @@ static void alc880_lg_lw_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) @@ -2363,11 +2336,10 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); - val = ucontrol->value.enumerated.item[0] >= 3 ? 0x80 : 0x00; - snd_hda_codec_amp_update(codec, nid, 0, HDA_OUTPUT, 0, - 0x80, val); - snd_hda_codec_amp_update(codec, nid, 1, HDA_OUTPUT, 0, - 0x80, val); + val = ucontrol->value.enumerated.item[0] >= 3 ? + HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); return 1; } return 0; @@ -4791,13 +4763,10 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x00 : 0x80; - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, - imux->items[i].index, - 0x80, v); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, imux->items[i].index, - 0x80, v); + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -5134,14 +5103,10 @@ static void alc885_imac24_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* Processes unsolicited events. */ @@ -5178,10 +5143,8 @@ static void alc882_targa_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); } @@ -5776,13 +5739,10 @@ static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol, if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x00 : 0x80; - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, imux->items[i].index, - 0x80, v); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, - imux->items[i].index, - 0x80, v); + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -6421,15 +6381,10 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* toggle RCA according to the front-jack state */ @@ -6439,12 +6394,10 @@ static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } + static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -6483,10 +6436,8 @@ static void alc883_medion_md2_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } static void alc883_medion_md2_unsol_event(struct hda_codec *codec, @@ -6504,11 +6455,9 @@ static void alc883_tagra_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); } @@ -6526,11 +6475,9 @@ static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) @@ -6540,15 +6487,11 @@ static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, @@ -7347,18 +7290,13 @@ static void alc262_hippo_automute(struct hda_codec *codec) spec->jack_present = (present & 0x80000000) != 0; if (spec->jack_present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7382,18 +7320,13 @@ static void alc262_hippo1_automute(struct hda_codec *codec) present = (present & 0x80000000) != 0; if (present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7455,18 +7388,13 @@ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) } if (spec->jack_present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7488,13 +7416,13 @@ static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); return change; } @@ -7507,9 +7435,11 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); if (change) alc262_fujitsu_automute(codec, 0); return change; @@ -8331,11 +8261,10 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x00 : 0x80; - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, - imux->items[i].index, 0x80, v); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, - imux->items[i].index, 0x80, v); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx ); @@ -9328,14 +9257,10 @@ static void alc861_toshiba_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); } static void alc861_toshiba_unsol_event(struct hda_codec *codec, @@ -9922,11 +9847,10 @@ static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x00 : 0x80; - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, - imux->items[i].index, 0x80, v); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, - imux->items[i].index, 0x80, v); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -10261,11 +10185,9 @@ static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) @@ -10275,11 +10197,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, + HDA_AMP_MUTE, bits); } static void alc861vd_lenovo_automute(struct hda_codec *codec) @@ -10353,10 +10273,8 @@ static void alc861vd_dallas_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) @@ -10855,11 +10773,10 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x00 : 0x80; - snd_hda_codec_amp_update(codec, nid, 0, HDA_INPUT, - imux->items[i].index, 0x80, v); - snd_hda_codec_amp_update(codec, nid, 1, HDA_INPUT, - imux->items[i].index, 0x80, v); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -11204,11 +11121,9 @@ static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) @@ -11218,15 +11133,11 @@ static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 145a5f3c0632..1690726c1e13 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2408,13 +2408,13 @@ static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); + HDA_AMP_VOLMASK, valp[0]); snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); + HDA_AMP_VOLMASK, valp[1]); return change; } @@ -2427,13 +2427,15 @@ static int vaio_master_sw_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); + HDA_AMP_MUTE, + (valp[0] ? 0 : HDA_AMP_MUTE)); change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); + HDA_AMP_MUTE, + (valp[1] ? 0 : HDA_AMP_MUTE)); snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); + HDA_AMP_MUTE, (valp[0] ? 0 : HDA_AMP_MUTE)); snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); + HDA_AMP_MUTE, (valp[1] ? 0 : HDA_AMP_MUTE)); return change; } -- cgit v1.2.3 From cca3b3718ca96dca51daf1129ac03003bcede751 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2007 17:12:15 +0200 Subject: [ALSA] hda-codec - Clean up bind-controls We have already a generic bind-control helper, so let's clean up the codes using it. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 34 +++++----------- sound/pci/hda/patch_conexant.c | 68 +++++++++----------------------- sound/pci/hda/patch_realtek.c | 35 +++++------------ sound/pci/hda/patch_sigmatel.c | 89 ++++++++++-------------------------------- 4 files changed, 56 insertions(+), 170 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index febc2053f08e..f9390a544ea4 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1127,23 +1127,14 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x05 and 0x06 */ -static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - return change; -} +static struct hda_bind_ctls ad1981_hp_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* mute internal speaker if HP is plugged */ static void ad1981_hp_automute(struct hda_codec *codec) @@ -1204,14 +1195,7 @@ static struct hda_input_mux ad1981_hp_capture_source = { }; static struct snd_kcontrol_new ad1981_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1981_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ebf83275756e..080e3001d9c5 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -483,23 +483,14 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x10 and 0x11 */ -static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - return change; -} +static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* toggle input of built-in and mic jack appropriately */ static void cxt5045_hp_automic(struct hda_codec *codec) @@ -567,14 +558,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5045_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -897,23 +881,14 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, } /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ -static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - return change; -} +static struct hda_bind_ctls cxt5047_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* mute internal speaker if HP is plugged */ static void cxt5047_hp_automute(struct hda_codec *codec) @@ -1035,14 +1010,7 @@ static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5047_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 29119fd4017d..ebbabeb32930 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7408,23 +7408,14 @@ static void alc262_fujitsu_unsol_event(struct hda_codec *codec, } /* bind volumes of both NID 0x0c and 0x0d */ -static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - return change; -} +static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* bind hp and internal speaker mute (with plug check) */ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, @@ -7446,15 +7437,7 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, } static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = alc262_fujitsu_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1690726c1e13..bf5d91b63d15 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2400,63 +2400,28 @@ static struct hda_verb vaio_ar_init[] = { }; /* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[0]); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - HDA_AMP_VOLMASK, valp[1]); - return change; -} +static struct hda_bind_ctls vaio_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - (valp[0] ? 0 : HDA_AMP_MUTE)); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - (valp[1] ? 0 : HDA_AMP_MUTE)); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - HDA_AMP_MUTE, (valp[0] ? 0 : HDA_AMP_MUTE)); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - HDA_AMP_MUTE, (valp[1] ? 0 : HDA_AMP_MUTE)); - return change; -} +static struct hda_bind_ctls vaio_bind_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0, + }, +}; static struct snd_kcontrol_new vaio_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -2472,22 +2437,8 @@ static struct snd_kcontrol_new vaio_mixer[] = { }; static struct snd_kcontrol_new vaio_ar_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), -- cgit v1.2.3 From cb53c626e1145edf1d619bc4953f6293d3a77ace Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2007 17:21:45 +0200 Subject: [ALSA] hda-intel - Add POWER_SAVE option Added CONFIG_SND_HDA_POWER_SAVE kconfig. It's an experimental option to achieve an aggressive power-saving. With this option, the driver will turn on/off the power of each codec and controller chip dynamically on demand. The patch introduces a new module option 'power_save'. It specifies the second of time-out for automatic power-down. As default, it's 10 seconds. Setting 0 means to suppress the power-saving feature. The codec may have analog-input loopbacks, which are usually represented by mixer elements such as 'Mic Playback Switch' or 'CD Playback Switch'. When these are on, we cannot turn off the mixer and the codec chip has to be kept on. For bookkeeping these states, a new codec-callback is introduced. For the bus-controller side, a new callback pm_notify is introduced, which can be used to turn on/off the contoller appropriately. Note that this power-saving might cause slight click-noise at power-on/off. Also, it might take some time to wake up the codec, and might even drop some tones at the very beginning. This seems to be the side-effect of turning off the controller chip. This turn-off of the controller can be disabled by undefining HDA_POWER_SAVE_RESET_CONTOLLER in hda_intel.c. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 239 ++++++++++++++++++++++++++------ sound/pci/hda/hda_codec.h | 32 ++++- sound/pci/hda/hda_generic.c | 55 +++++++- sound/pci/hda/hda_intel.c | 158 ++++++++++++++++----- sound/pci/hda/hda_local.h | 25 +++- sound/pci/hda/hda_proc.c | 3 + sound/pci/hda/patch_analog.c | 91 ++++++++++++ sound/pci/hda/patch_realtek.c | 307 +++++++++++++++++++++++++++++------------ sound/pci/hda/patch_sigmatel.c | 6 +- sound/pci/hda/patch_via.c | 68 +++++++-- 10 files changed, 792 insertions(+), 192 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 043529308676..9a3b72824f87 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -33,6 +33,13 @@ #include "hda_local.h" #include +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* define this option here to hide as static */ +static int power_save = 10; +module_param(power_save, int, 0644); +MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); +#endif /* * vendor / preset table @@ -60,6 +67,13 @@ static struct hda_vendor_id hda_vendor_ids[] = { #include "hda_patch.h" +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_power_work(struct work_struct *work); +static void hda_keep_power_on(struct hda_codec *codec); +#else +static inline void hda_keep_power_on(struct hda_codec *codec) {} +#endif + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -77,12 +91,14 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, unsigned int verb, unsigned int parm) { unsigned int res; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) res = codec->bus->ops.get_response(codec); else res = (unsigned int)-1; mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return res; } @@ -102,9 +118,11 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { int err; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); err = codec->bus->ops.command(codec, nid, direct, verb, parm); mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return err; } @@ -505,6 +523,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); +#endif list_del(&codec->list); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) @@ -551,6 +572,15 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); +#ifdef CONFIG_SND_HDA_POWER_SAVE + INIT_DELAYED_WORK(&codec->power_work, hda_power_work); + /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. + * the caller has to power down appropriatley after initialization + * phase. + */ + hda_keep_power_on(codec); +#endif + list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -855,7 +885,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, return ret; } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { @@ -879,7 +909,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } -#endif /* CONFIG_PM */ +#endif /* SND_HDA_NEEDS_RESUME */ /* * AMP control callbacks @@ -945,6 +975,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change = 0; + snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 0x7f, *valp); @@ -953,6 +984,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 0x7f, *valp); + snd_hda_power_down(codec); return change; } @@ -1025,6 +1057,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change = 0; + snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, HDA_AMP_MUTE, @@ -1035,7 +1068,11 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, HDA_AMP_MUTE, *valp ? 0 : HDA_AMP_MUTE); - +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, nid); +#endif + snd_hda_power_down(codec); return change; } @@ -1502,7 +1539,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) return 0; } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /* * command cache */ @@ -1528,6 +1565,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { int err; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); err = codec->bus->ops.command(codec, nid, direct, verb, parm); if (!err) { @@ -1538,6 +1576,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, c->val = parm; } mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return err; } @@ -1572,7 +1611,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } -#endif /* CONFIG_PM */ +#endif /* SND_HDA_NEEDS_RESUME */ /* * set power state of the codec @@ -1580,24 +1619,70 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state) { - hda_nid_t nid, nid_start; - int nodes; + hda_nid_t nid; + int i; snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); - nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { if (get_wcaps(codec, nid) & AC_WCAP_POWER) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, power_state); } - if (power_state == AC_PWRST_D0) + if (power_state == AC_PWRST_D0) { + unsigned long end_time; + int state; msleep(10); + /* wait until the codec reachs to D0 */ + end_time = jiffies + msecs_to_jiffies(500); + do { + state = snd_hda_codec_read(codec, fg, 0, + AC_VERB_GET_POWER_STATE, 0); + if (state == power_state) + break; + msleep(1); + } while (time_after_eq(end_time, jiffies)); + } +} + +#ifdef SND_HDA_NEEDS_RESUME +/* + * call suspend and power-down; used both from PM and power-save + */ +static void hda_call_codec_suspend(struct hda_codec *codec) +{ + if (codec->patch_ops.suspend) + codec->patch_ops.suspend(codec, PMSG_SUSPEND); + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D3); +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); +#endif } +/* + * kick up codec; used both from PM and power-save + */ +static void hda_call_codec_resume(struct hda_codec *codec) +{ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D0); + if (codec->patch_ops.resume) + codec->patch_ops.resume(codec); + else { + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + } +} +#endif /* SND_HDA_NEEDS_RESUME */ + /** * snd_hda_build_controls - build mixer controls @@ -1611,28 +1696,24 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; - /* build controls */ list_for_each_entry(codec, &bus->codec_list, list) { - int err; - if (!codec->patch_ops.build_controls) - continue; - err = codec->patch_ops.build_controls(codec); - if (err < 0) - return err; - } - - /* initialize */ - list_for_each_entry(codec, &bus->codec_list, list) { - int err; + int err = 0; + /* fake as if already powered-on */ + hda_keep_power_on(codec); + /* then fire up */ hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); - if (!codec->patch_ops.init) - continue; - err = codec->patch_ops.init(codec); + /* continue to initialize... */ + if (codec->patch_ops.init) + err = codec->patch_ops.init(codec); + if (!err && codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + snd_hda_power_down(codec); if (err < 0) return err; } + return 0; } @@ -2078,7 +2159,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, */ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) { - int err; + int err; for (; knew->name; knew++) { struct snd_kcontrol *kctl; @@ -2101,6 +2182,89 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state); + +static void hda_power_work(struct work_struct *work) +{ + struct hda_codec *codec = + container_of(work, struct hda_codec, power_work.work); + + if (!codec->power_on || codec->power_count) + return; + + hda_call_codec_suspend(codec); + codec->power_on = 0; + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); +} + +static void hda_keep_power_on(struct hda_codec *codec) +{ + codec->power_count++; + codec->power_on = 1; +} + +void snd_hda_power_up(struct hda_codec *codec) +{ + codec->power_count++; + if (codec->power_on) + return; + + codec->power_on = 1; + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); + hda_call_codec_resume(codec); + cancel_delayed_work(&codec->power_work); +} + +void snd_hda_power_down(struct hda_codec *codec) +{ + --codec->power_count; + if (!codec->power_on) + return; + if (power_save) + schedule_delayed_work(&codec->power_work, + msecs_to_jiffies(power_save * 1000)); +} + +int snd_hda_check_amp_list_power(struct hda_codec *codec, + struct hda_loopback_check *check, + hda_nid_t nid) +{ + struct hda_amp_list *p; + int ch, v; + + if (!check->amplist) + return 0; + for (p = check->amplist; p->nid; p++) { + if (p->nid == nid) + break; + } + if (!p->nid) + return 0; /* nothing changed */ + + for (p = check->amplist; p->nid; p++) { + for (ch = 0; ch < 2; ch++) { + v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, + p->idx); + if (!(v & HDA_AMP_MUTE) && v > 0) { + if (!check->power_on) { + check->power_on = 1; + snd_hda_power_up(codec); + } + return 1; + } + } + } + if (check->power_on) { + check->power_on = 0; + snd_hda_power_down(codec); + } + return 0; +} +#endif /* * Channel mode helper @@ -2605,41 +2769,32 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) { struct hda_codec *codec; - /* FIXME: should handle power widget capabilities */ list_for_each_entry(codec, &bus->codec_list, list) { - if (codec->patch_ops.suspend) - codec->patch_ops.suspend(codec, state); - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D3); + hda_call_codec_suspend(codec); } return 0; } +#ifndef CONFIG_SND_HDA_POWER_SAVE /** * snd_hda_resume - resume the codecs * @bus: the HDA bus * @state: resume state * * Returns 0 if successful. + * + * This fucntion is defined only when POWER_SAVE isn't set. + * In the power-save mode, the codec is resumed dynamically. */ int snd_hda_resume(struct hda_bus *bus) { struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - if (codec->patch_ops.resume) - codec->patch_ops.resume(codec); - else { - codec->patch_ops.init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - } + hda_call_codec_resume(codec); } return 0; } +#endif /* !CONFIG_SND_HDA_POWER_SAVE */ #endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 92938d2a52e2..1ffffaa3a30d 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -26,6 +26,10 @@ #include #include +#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) +#define SND_HDA_NEEDS_RESUME /* resume control code is required */ +#endif + /* * nodes */ @@ -412,6 +416,10 @@ struct hda_bus_ops { unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + /* notify power-up/down from codec to contoller */ + void (*pm_notify)(struct hda_codec *codec); +#endif }; /* template to pass to the bus constructor */ @@ -473,10 +481,13 @@ struct hda_codec_ops { int (*init)(struct hda_codec *codec); void (*free)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME int (*suspend)(struct hda_codec *codec, pm_message_t state); int (*resume)(struct hda_codec *codec); #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE + int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); +#endif }; /* record for amp information cache */ @@ -573,6 +584,12 @@ struct hda_codec { unsigned int spdif_in_enable; /* SPDIF input enable? */ struct snd_hwdep *hwdep; /* assigned hwdep device */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE + int power_on; /* current (global) power-state */ + int power_count; /* current (global) power refcount */ + struct delayed_work power_work; /* delayed task for powerdown */ +#endif }; /* direction */ @@ -617,7 +634,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); /* cached write */ -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, @@ -662,4 +679,15 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); int snd_hda_resume(struct hda_bus *bus); #endif +/* + * power saving + */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +void snd_hda_power_up(struct hda_codec *codec); +void snd_hda_power_down(struct hda_codec *codec); +#else +static inline void snd_hda_power_up(struct hda_codec *codec) {} +static inline void snd_hda_power_down(struct hda_codec *codec) {} +#endif + #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 91cd9b9ea5d1..819c804a579f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -70,6 +70,13 @@ struct hda_gspec { struct hda_pcm pcm_rec; /* PCM information */ struct list_head nid_list; /* list of widgets */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define MAX_LOOPBACK_AMPS 7 + struct hda_loopback_check loopback; + int num_loopbacks; + struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; +#endif }; /* @@ -682,11 +689,33 @@ static int parse_input(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx) +{ + struct hda_gspec *spec = codec->spec; + struct hda_amp_list *p; + + if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { + snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); + return; + } + p = &spec->loopback_list[spec->num_loopbacks++]; + p->nid = nid; + p->dir = dir; + p->idx = idx; + spec->loopback.amplist = spec->loopback_list; +} +#else +#define add_input_loopback(codec,nid,dir,idx) +#endif + /* * create mixer controls if possible */ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index, const char *type, const char *dir_sfx) + unsigned int index, const char *type, + const char *dir_sfx, int is_loopback) { char name[32]; int err; @@ -700,6 +729,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if ((node->wid_caps & AC_WCAP_IN_AMP) && (node->amp_in_caps & AC_AMPCAP_MUTE)) { knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); + if (is_loopback) + add_input_loopback(codec, node->nid, HDA_INPUT, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; @@ -707,6 +738,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && (node->amp_out_caps & AC_AMPCAP_MUTE)) { knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); + if (is_loopback) + add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; @@ -765,7 +798,7 @@ static int create_output_mixers(struct hda_codec *codec, const char **names) for (i = 0; i < spec->pcm_vol_nodes; i++) { err = create_mixer(codec, spec->pcm_vol[i].node, spec->pcm_vol[i].index, - names[i], "Playback"); + names[i], "Playback", 0); if (err < 0) return err; } @@ -782,7 +815,7 @@ static int build_output_controls(struct hda_codec *codec) case 1: return create_mixer(codec, spec->pcm_vol[0].node, spec->pcm_vol[0].index, - "Master", "Playback"); + "Master", "Playback", 0); case 2: if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) return create_output_mixers(codec, types_speaker); @@ -818,7 +851,7 @@ static int build_input_controls(struct hda_codec *codec) if (spec->input_mux.num_items == 1) { err = create_mixer(codec, adc_node, spec->input_mux.items[0].index, - NULL, "Capture"); + NULL, "Capture", 0); if (err < 0) return err; return 0; @@ -884,7 +917,8 @@ static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, return err; else if (err >= 1) { if (err == 1) { - err = create_mixer(codec, node, i, type, "Playback"); + err = create_mixer(codec, node, i, type, + "Playback", 1); if (err < 0) return err; if (err > 0) @@ -1020,6 +1054,14 @@ static int build_generic_pcms(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_gspec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* */ @@ -1027,6 +1069,9 @@ static struct hda_codec_ops generic_patch_ops = { .build_controls = build_generic_controls, .build_pcms = build_generic_pcms, .free = snd_hda_generic_free, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = generic_check_power_status, +#endif }; /* diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ebb442dcc027..7be3a9b55330 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -75,6 +75,7 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " module_param(enable_msi, int, 0); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); +/* power_save option is defined in hda_codec.c */ /* just for backward compatibility */ static int enable; @@ -101,6 +102,18 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " +/* + * build flags + */ + +/* + * reset the HD-audio controller in power save mode. + * this may give more power-saving, but will take longer time to + * wake up. + */ +#define HDA_POWER_SAVE_RESET_CONTROLLER + + /* * registers */ @@ -345,6 +358,7 @@ struct azx { /* flags */ int position_fix; + unsigned int running :1; unsigned int initialized :1; unsigned int single_cmd :1; unsigned int polling_mode :1; @@ -665,6 +679,9 @@ static unsigned int azx_get_response(struct hda_codec *codec) return azx_rirb_get_response(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void azx_power_notify(struct hda_codec *codec); +#endif /* reset codec link */ static int azx_reset(struct azx *chip) @@ -790,19 +807,12 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) /* - * initialize the chip + * reset and start the controller registers */ static void azx_init_chip(struct azx *chip) { - unsigned char reg; - - /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio - * codecs - */ - pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); - pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); + if (chip->initialized) + return; /* reset controller */ azx_reset(chip); @@ -819,22 +829,45 @@ static void azx_init_chip(struct azx *chip) azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); + chip->initialized = 1; +} + +/* + * initialize the PCI registers + */ +/* update bits in a PCI register byte */ +static void update_pci_byte(struct pci_dev *pci, unsigned int reg, + unsigned char mask, unsigned char val) +{ + unsigned char data; + + pci_read_config_byte(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_byte(pci, reg, data); +} + +static void azx_init_pci(struct azx *chip) +{ + /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio + * codecs + */ + update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + switch (chip->driver_type) { case AZX_DRIVER_ATI: /* For ATI SB450 azalia HD audio, we need to enable snoop */ - pci_read_config_byte(chip->pci, - ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - ®); - pci_write_config_byte(chip->pci, - ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - (reg & 0xf8) | - ATI_SB450_HDAUDIO_ENABLE_SNOOP); + update_pci_byte(chip->pci, + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); break; case AZX_DRIVER_NVIDIA: /* For NVIDIA HDA, enable snoop */ - pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, ®); - pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, - (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS); + update_pci_byte(chip->pci, + NVIDIA_HDA_TRANSREG_ADDR, + 0x0f, NVIDIA_HDA_ENABLE_COHBITS); break; } } @@ -1007,6 +1040,9 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; +#ifdef CONFIG_SND_HDA_POWER_SAVE + bus_temp.ops.pm_notify = azx_power_notify; +#endif err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); if (err < 0) @@ -1128,9 +1164,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) 128); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); + snd_hda_power_up(apcm->codec); err = hinfo->ops.open(hinfo, apcm->codec, substream); if (err < 0) { azx_release_device(azx_dev); + snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return err; } @@ -1159,6 +1197,7 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); hinfo->ops.close(hinfo, apcm->codec, substream); + snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return 0; } @@ -1459,6 +1498,48 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) } +static void azx_stop_chip(struct azx *chip) +{ + if (chip->initialized) + return; + + /* disable interrupts */ + azx_int_disable(chip); + azx_int_clear(chip); + + /* disable CORB/RIRB */ + azx_free_cmd_io(chip); + + /* disable position buffer */ + azx_writel(chip, DPLBASE, 0); + azx_writel(chip, DPUBASE, 0); + + chip->initialized = 0; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* power-up/down the controller */ +static void azx_power_notify(struct hda_codec *codec) +{ + struct azx *chip = codec->bus->private_data; + struct hda_codec *c; + int power_on = 0; + + list_for_each_entry(c, &codec->bus->codec_list, list) { + if (c->power_on) { + power_on = 1; + break; + } + } + if (power_on) + azx_init_chip(chip); +#ifdef HDA_POWER_SAVE_RESET_CONTROLLER + else if (chip->running) + azx_stop_chip(chip); +#endif +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #ifdef CONFIG_PM /* * power management @@ -1473,7 +1554,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); snd_hda_suspend(chip->bus, state); - azx_free_cmd_io(chip); + azx_stop_chip(chip); if (chip->irq >= 0) { synchronize_irq(chip->irq); free_irq(chip->irq, chip); @@ -1506,8 +1587,12 @@ static int azx_resume(struct pci_dev *pci) chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; + azx_init_pci(chip); +#ifndef CONFIG_SND_HDA_POWER_SAVE + /* the explicit resume is needed only when POWER_SAVE isn't set */ azx_init_chip(chip); snd_hda_resume(chip->bus); +#endif snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -1521,20 +1606,9 @@ static int azx_free(struct azx *chip) { if (chip->initialized) { int i; - for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); + azx_stop_chip(chip); } if (chip->irq >= 0) { @@ -1720,10 +1794,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, azx_init_stream(chip); /* initialize chip */ + azx_init_pci(chip); azx_init_chip(chip); - chip->initialized = 1; - /* codec detection */ if (!chip->codec_mask) { snd_printk(KERN_ERR SFX "no codecs found!\n"); @@ -1750,6 +1823,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, return err; } +static void power_down_all_codecs(struct azx *chip) +{ +#ifdef CONFIG_SND_HDA_POWER_SAVE + /* The codecs were powered up in snd_hda_codec_new(). + * Now all initialization done, so turn them down if possible + */ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) { + snd_hda_power_down(codec); + } +#endif +} + static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -1800,6 +1886,8 @@ static int __devinit azx_probe(struct pci_dev *pci, } pci_set_drvdata(pci, card); + chip->running = 1; + power_down_all_codecs(chip); return err; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 35ea0cf37a27..a79d0ed5469c 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -86,7 +86,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, int mask, int val); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME void snd_hda_codec_resume_amp(struct hda_codec *codec); #endif @@ -366,4 +366,27 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, */ int snd_hda_create_hwdep(struct hda_codec *codec); +/* + * power-management + */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +void snd_hda_schedule_power_save(struct hda_codec *codec); + +struct hda_amp_list { + hda_nid_t nid; + unsigned char dir; + unsigned char idx; +}; + +struct hda_loopback_check { + struct hda_amp_list *amplist; + int power_on; +}; + +int snd_hda_check_amp_list_power(struct hda_codec *codec, + struct hda_loopback_check *check, + hda_nid_t nid); +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ccd19180e541..e94944f34ffd 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -262,6 +262,7 @@ static void print_codec_info(struct snd_info_entry *entry, if (! codec->afg) return; + snd_hda_power_up(codec); snd_iprintf(buffer, "Default PCM:\n"); print_pcm_caps(buffer, codec, codec->afg); snd_iprintf(buffer, "Default Amp-In caps: "); @@ -272,6 +273,7 @@ static void print_codec_info(struct snd_info_entry *entry, nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (! nid || nodes < 0) { snd_iprintf(buffer, "Invalid AFG subtree\n"); + snd_hda_power_down(codec); return; } for (i = 0; i < nodes; i++, nid++) { @@ -359,6 +361,7 @@ static void print_codec_info(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } } + snd_hda_power_down(codec); } /* diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index f9390a544ea4..53cfa0da4964 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -73,6 +73,10 @@ struct ad198x_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; /* @@ -144,6 +148,14 @@ static int ad198x_build_controls(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* * Analog playback callbacks */ @@ -323,6 +335,9 @@ static struct hda_codec_ops ad198x_patch_ops = { .build_pcms = ad198x_build_pcms, .init = ad198x_init, .free = ad198x_free, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = ad198x_check_power_status, +#endif }; @@ -736,6 +751,17 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { {} }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1986a_loopbacks[] = { + { 0x13, HDA_OUTPUT, 0 }, /* Mic */ + { 0x14, HDA_OUTPUT, 0 }, /* Phone */ + { 0x15, HDA_OUTPUT, 0 }, /* CD */ + { 0x16, HDA_OUTPUT, 0 }, /* Aux */ + { 0x17, HDA_OUTPUT, 0 }, /* Line */ + { } /* end */ +}; +#endif + static int patch_ad1986a(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -759,6 +785,9 @@ static int patch_ad1986a(struct hda_codec *codec) spec->mixers[0] = ad1986a_mixers; spec->num_init_verbs = 1; spec->init_verbs[0] = ad1986a_init_verbs; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1986a_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -944,6 +973,13 @@ static struct hda_verb ad1983_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1983_loopbacks[] = { + { 0x12, HDA_OUTPUT, 0 }, /* Mic */ + { 0x13, HDA_OUTPUT, 0 }, /* Line */ + { } /* end */ +}; +#endif static int patch_ad1983(struct hda_codec *codec) { @@ -968,6 +1004,9 @@ static int patch_ad1983(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1983_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1983_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -1091,6 +1130,17 @@ static struct hda_verb ad1981_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1981_loopbacks[] = { + { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ + { 0x13, HDA_OUTPUT, 0 }, /* Line */ + { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ + { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ + { 0x1d, HDA_OUTPUT, 0 }, /* CD */ + { } /* end */ +}; +#endif + /* * Patch for HP nx6320 * @@ -1350,6 +1400,9 @@ static int patch_ad1981(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1981_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1981_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -2103,6 +2156,15 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) snd_hda_sequence_write(codec, ad1988_laptop_hp_off); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1988_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Line */ + { 0x20, HDA_INPUT, 4 }, /* Mic */ + { 0x20, HDA_INPUT, 6 }, /* CD */ + { } /* end */ +}; +#endif /* * Automatic parse of I/O pins from the BIOS configuration @@ -2647,6 +2709,9 @@ static int patch_ad1988(struct hda_codec *codec) codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; break; } +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1988_loopbacks; +#endif return 0; } @@ -2803,6 +2868,16 @@ static struct hda_verb ad1884_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1884_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Mic */ + { 0x20, HDA_INPUT, 2 }, /* CD */ + { 0x20, HDA_INPUT, 4 }, /* Docking */ + { } /* end */ +}; +#endif + static int patch_ad1884(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -2827,6 +2902,9 @@ static int patch_ad1884(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1884_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1884_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -3208,6 +3286,16 @@ static struct hda_verb ad1882_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1882_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Mic */ + { 0x20, HDA_INPUT, 4 }, /* Line */ + { 0x20, HDA_INPUT, 6 }, /* CD */ + { } /* end */ +}; +#endif + /* models */ enum { AD1882_3STACK, @@ -3246,6 +3334,9 @@ static int patch_ad1882(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1882_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1882_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ebbabeb32930..b3d3916c8eca 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -240,6 +240,10 @@ struct alc_spec { /* for pin sensing */ unsigned int sense_updated: 1; unsigned int jack_present: 1; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; /* @@ -264,6 +268,9 @@ struct alc_config_preset { const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); void (*init_hook)(struct hda_codec *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_amp_list *loopbacks; +#endif }; @@ -621,6 +628,9 @@ static void setup_preset(struct alc_spec *spec, spec->unsol_event = preset->unsol_event; spec->init_hook = preset->init_hook; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = preset->loopbacks; +#endif } /* Enable GPIO mask and set output */ @@ -1287,11 +1297,13 @@ static struct hda_verb alc880_volume_init_verbs[] = { * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* * Set up output mixers (0x0c - 0x0f) @@ -1836,8 +1848,8 @@ static struct hda_verb alc880_lg_init_verbs[] = { {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* mute all amp mixer inputs */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* line-in to input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -1939,7 +1951,7 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* speaker-out */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -1979,6 +1991,24 @@ static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) alc880_lg_lw_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc880_loopbacks[] = { + { 0x0b, HDA_INPUT, 0 }, + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 2 }, + { 0x0b, HDA_INPUT, 3 }, + { 0x0b, HDA_INPUT, 4 }, + { } /* end */ +}; + +static struct hda_amp_list alc880_lg_loopbacks[] = { + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 6 }, + { 0x0b, HDA_INPUT, 7 }, + { } /* end */ +}; +#endif + /* * Common callbacks */ @@ -2005,6 +2035,14 @@ static void alc_unsol_event(struct hda_codec *codec, unsigned int res) spec->unsol_event(codec, res); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct alc_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* * Analog playback callbacks */ @@ -2236,6 +2274,9 @@ static struct hda_codec_ops alc_patch_ops = { .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = alc_check_power_status, +#endif }; @@ -2860,6 +2901,9 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_lg_capture_source, .unsol_event = alc880_lg_unsol_event, .init_hook = alc880_lg_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .loopbacks = alc880_lg_loopbacks, +#endif }, [ALC880_LG_LW] = { .mixers = { alc880_lg_lw_mixer }, @@ -3343,6 +3387,10 @@ static int patch_alc880(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC880_AUTO) spec->init_hook = alc880_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc880_loopbacks; +#endif return 0; } @@ -3691,12 +3739,12 @@ static struct hda_verb alc260_init_verbs[] = { /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* mute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* mute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* mute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* mute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -3741,12 +3789,12 @@ static struct hda_verb alc260_hp_init_verbs[] = { /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, @@ -3791,12 +3839,12 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = { /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, @@ -4418,11 +4466,12 @@ static struct hda_verb alc260_volume_init_verbs[] = { * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x08 - 0x0a) @@ -4499,6 +4548,17 @@ static void alc260_auto_init(struct hda_codec *codec) alc260_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc260_loopbacks[] = { + { 0x07, HDA_INPUT, 0 }, + { 0x07, HDA_INPUT, 1 }, + { 0x07, HDA_INPUT, 2 }, + { 0x07, HDA_INPUT, 3 }, + { 0x07, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + /* * ALC260 configurations */ @@ -4698,6 +4758,10 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) spec->init_hook = alc260_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc260_loopbacks; +#endif return 0; } @@ -5223,17 +5287,17 @@ static struct hda_verb alc882_auto_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -5322,6 +5386,10 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc882_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc882_pcm_analog_playback alc880_pcm_analog_playback #define alc882_pcm_analog_capture alc880_pcm_analog_capture @@ -5659,6 +5727,10 @@ static int patch_alc882(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC882_AUTO) spec->init_hook = alc882_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc882_loopbacks; +#endif return 0; } @@ -6242,11 +6314,12 @@ static struct hda_verb alc883_init_verbs[] = { {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* mute analog input loopbacks */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -6515,17 +6588,17 @@ static struct hda_verb alc883_auto_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -6588,6 +6661,10 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc883_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc883_pcm_analog_playback alc880_pcm_analog_playback #define alc883_pcm_analog_capture alc880_pcm_analog_capture @@ -7029,6 +7106,10 @@ static int patch_alc883(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC883_AUTO) spec->init_hook = alc883_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc883_loopbacks; +#endif return 0; } @@ -7186,17 +7267,17 @@ static struct hda_verb alc262_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0e) @@ -7565,17 +7646,17 @@ static struct hda_verb alc262_volume_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -7626,19 +7707,19 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* * Set up output mixers (0x0c - 0x0e) @@ -7713,20 +7794,20 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for front * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* * Set up output mixers (0x0c - 0x0e) */ @@ -7796,6 +7877,10 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { { } }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc262_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc262_pcm_analog_playback alc880_pcm_analog_playback #define alc262_pcm_analog_capture alc880_pcm_analog_capture @@ -8098,6 +8183,10 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) spec->init_hook = alc262_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; +#endif return 0; } @@ -8507,6 +8596,10 @@ static void alc268_auto_init(struct hda_codec *codec) alc268_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc883_loopbacks alc880_loopbacks +#endif + /* * configuration and preset */ @@ -9556,6 +9649,16 @@ static void alc861_auto_init(struct hda_codec *codec) alc861_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc861_loopbacks[] = { + { 0x15, HDA_INPUT, 0 }, + { 0x15, HDA_INPUT, 1 }, + { 0x15, HDA_INPUT, 2 }, + { 0x15, HDA_INPUT, 3 }, + { } /* end */ +}; +#endif + /* * configuration and preset @@ -9753,6 +9856,10 @@ static int patch_alc861(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) spec->init_hook = alc861_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861_loopbacks; +#endif return 0; } @@ -10035,11 +10142,11 @@ static struct hda_verb alc861vd_volume_init_verbs[] = { * the analog-loopback mixer widget */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -10266,6 +10373,10 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re alc861vd_dallas_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc861vd_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture @@ -10688,6 +10799,10 @@ static int patch_alc861vd(struct hda_codec *codec) if (board_config == ALC861VD_AUTO) spec->init_hook = alc861vd_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861vd_loopbacks; +#endif return 0; } @@ -10968,11 +11083,11 @@ static struct hda_verb alc662_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -11041,11 +11156,11 @@ static struct hda_verb alc662_auto_init_verbs[] = { * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -11132,6 +11247,10 @@ static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, alc662_lenovo_101e_ispeaker_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc662_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc662_pcm_analog_playback alc880_pcm_analog_playback @@ -11534,6 +11653,10 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc662_loopbacks; +#endif return 0; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bf5d91b63d15..4a981399abde 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1946,7 +1946,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { stac92xx_set_config_regs(codec); @@ -1963,7 +1963,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { .init = stac92xx_init, .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .resume = stac92xx_resume, #endif }; @@ -2460,7 +2460,7 @@ static struct hda_codec_ops stac9872_patch_ops = { .build_pcms = stac92xx_build_pcms, .init = stac92xx_init, .free = stac92xx_free, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .resume = stac92xx_resume, #endif }; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6c734f07e5b5..33b5e1ffa817 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -115,6 +115,10 @@ struct via_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; static hda_nid_t vt1708_adc_nids[2] = { @@ -305,15 +309,15 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x19 - 0x1b) @@ -543,6 +547,14 @@ static int via_init(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct via_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* */ static struct hda_codec_ops via_patch_ops = { @@ -550,6 +562,9 @@ static struct hda_codec_ops via_patch_ops = { .build_pcms = via_build_pcms, .init = via_init, .free = via_free, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = via_check_power_status, +#endif }; /* fill in the dac_nids table from the parsed pin configuration */ @@ -738,6 +753,16 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1708_loopbacks[] = { + { 0x17, HDA_INPUT, 1 }, + { 0x17, HDA_INPUT, 2 }, + { 0x17, HDA_INPUT, 3 }, + { 0x17, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -831,6 +856,9 @@ static int patch_vt1708(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708_loopbacks; +#endif return 0; } @@ -871,15 +899,15 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output selector (0x1a, 0x1b, 0x29) @@ -1227,6 +1255,16 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) return 1; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1709_loopbacks[] = { + { 0x18, HDA_INPUT, 1 }, + { 0x18, HDA_INPUT, 2 }, + { 0x18, HDA_INPUT, 3 }, + { 0x18, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + static int patch_vt1709_10ch(struct hda_codec *codec) { struct via_spec *spec; @@ -1269,6 +1307,9 @@ static int patch_vt1709_10ch(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } @@ -1359,6 +1400,9 @@ static int patch_vt1709_6ch(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } -- cgit v1.2.3 From 95e99fdadb34debebd8dd35bb5a18b253dece22d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Aug 2007 15:29:04 +0200 Subject: [ALSA] hda-intel - Fix resume with power save The controller power wasn't turned on properly at resume due to the power-saving patch. Now fixed. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9a3b72824f87..efd56a3396bd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1662,6 +1662,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec) AC_PWRST_D3); #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); + codec->power_on = 0; #endif } @@ -2195,7 +2196,6 @@ static void hda_power_work(struct work_struct *work) return; hda_call_codec_suspend(codec); - codec->power_on = 0; if (codec->bus->ops.pm_notify) codec->bus->ops.pm_notify(codec); } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7be3a9b55330..f9c7c2e4f922 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1500,7 +1500,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) static void azx_stop_chip(struct azx *chip) { - if (chip->initialized) + if (!chip->initialized) return; /* disable interrupts */ -- cgit v1.2.3 From ae0a8ed8bf9c2edee4b831dee91ae914b9641fdd Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 13 Aug 2007 15:50:29 +0200 Subject: [ALSA] This patch adds more support for Dell systems with Stac9205 codecs. Tested against a couple of different systems (with different pin configs), but the others should also work. Also cleaned up some of the 9205 patch code. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 64 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4a981399abde..e096a48899c8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -44,7 +44,9 @@ enum { enum { STAC_9205_REF, - STAC_M43xx, + STAC_9205_DELL_M43, + STAC_9205_DELL_M44, + STAC_9205_M43xx, STAC_9205_MODELS }; @@ -788,23 +790,58 @@ static unsigned int ref9205_pin_configs[12] = { 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 }; +static unsigned int dell_m43_9205_pin_configs[12] = { + 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, + 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, + 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, +}; + +static unsigned int dell_m44_9205_pin_configs[12] = { + 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, + 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, + 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, +}; + + static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { - [STAC_REF] = ref9205_pin_configs, - [STAC_M43xx] = NULL, + [STAC_9205_REF] = ref9205_pin_configs, + [STAC_9205_DELL_M43] = dell_m43_9205_pin_configs, + [STAC_9205_DELL_M44] = dell_m44_9205_pin_configs, + [STAC_9205_M43xx] = NULL, }; static const char *stac9205_models[STAC_9205_MODELS] = { [STAC_9205_REF] = "ref", + [STAC_9205_DELL_M43] = "dell-m43", + [STAC_9205_DELL_M44] = "dell-m44", }; static struct snd_pci_quirk stac9205_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8, - "Dell Precision", STAC_M43xx), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff, - "Dell Precision", STAC_M43xx), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, + "Dell Precision", STAC_9205_M43xx), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, + "Dell Inspiron", STAC_9205_DELL_M44), {} /* terminator */ }; @@ -2312,7 +2349,9 @@ static int patch_stac9205(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; - if (spec->board_config == STAC_M43xx) { + switch (spec->board_config){ + case STAC_9205_M43xx: + case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ stac92xx_set_config_reg(codec, 0x1f, 0x01441030); stac92xx_set_config_reg(codec, 0x20, 0x1c410030); @@ -2322,9 +2361,12 @@ static int patch_stac9205(struct hda_codec *codec) * GPIO2 High = Headphone Mute */ spec->gpio_data = 0x00000005; - } else - spec->gpio_mask = spec->gpio_data = - 0x00000001; /* GPIO0 High = EAPD */ + break; + default: + /* GPIO0 High = EAPD */ + spec->gpio_mask = spec->gpio_data = 0x00000001; + break; + } stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); -- cgit v1.2.3 From dee1b66ce4f406d36fef70d1dd4360c5f1d26218 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 13 Aug 2007 16:10:30 +0200 Subject: [ALSA] hda-intel - Add power_save_controller module option Add power_save_controller module option instead of define flag. Also, added descriptions of new module options in ALSA-Configuration.txt. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f9c7c2e4f922..e20629a2d7d1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -75,8 +75,18 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " module_param(enable_msi, int, 0); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); +#ifdef CONFIG_SND_HDA_POWER_SAVE /* power_save option is defined in hda_codec.c */ +/* reset the HD-audio controller in power save mode. + * this may give more power-saving, but will take longer time to + * wake up. + */ +static int power_save_controller = 1; +module_param(power_save_controller, bool, 0644); +MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); +#endif + /* just for backward compatibility */ static int enable; module_param(enable, bool, 0444); @@ -102,17 +112,6 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " -/* - * build flags - */ - -/* - * reset the HD-audio controller in power save mode. - * this may give more power-saving, but will take longer time to - * wake up. - */ -#define HDA_POWER_SAVE_RESET_CONTROLLER - /* * registers @@ -1533,10 +1532,8 @@ static void azx_power_notify(struct hda_codec *codec) } if (power_on) azx_init_chip(chip); -#ifdef HDA_POWER_SAVE_RESET_CONTROLLER - else if (chip->running) + else if (chip->running && power_save_controller) azx_stop_chip(chip); -#endif } #endif /* CONFIG_SND_HDA_POWER_SAVE */ -- cgit v1.2.3 From 9d99f312629802f4c45306ee07618ee4978b4adc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Aug 2007 15:15:52 +0200 Subject: [ALSA] hda-intel - Fix NULL dereference in resume codec->patch_ops.init can be NULL. Check before calling it. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index efd56a3396bd..fc1ddf408b9b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1677,7 +1677,8 @@ static void hda_call_codec_resume(struct hda_codec *codec) if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { - codec->patch_ops.init(codec); + if (codec->patch_ops.init) + codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); } -- cgit v1.2.3 From 0b7a2e9cefd7614e68520127751f76583498df6c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Aug 2007 15:18:26 +0200 Subject: [ALSA] hda-intel - Don't do suspend if already powered down In the power-saving mode, the suspend is done dynamically at power-down. So we don't have to call suspend stuff explicitly if it's already powered down. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 4 ++++ sound/pci/hda/hda_intel.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index fc1ddf408b9b..0e923f3f0a80 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2771,6 +2771,10 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif hda_call_codec_suspend(codec); } return 0; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e20629a2d7d1..ab698336563c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1550,7 +1550,8 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); - snd_hda_suspend(chip->bus, state); + if (chip->initialized) + snd_hda_suspend(chip->bus, state); azx_stop_chip(chip); if (chip->irq >= 0) { synchronize_irq(chip->irq); -- cgit v1.2.3 From 765c24efa55752b715d9122f36eee485d4903839 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Aug 2007 15:43:06 +0200 Subject: [ALSA] hda-codec - Remove conflicting capture mixers for ALC861VD Removed conflicting capture mixers for ALC861VD model=dallas. It fixes the ALSA bug#3236. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b3d3916c8eca..171f64192dc8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10114,17 +10114,6 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, { } /* end */ }; -- cgit v1.2.3 From d1a991a682f6718db6c611ccfd36d903732d946c Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 15 Aug 2007 16:21:59 +0200 Subject: [ALSA] hda-codec - Update realtek codec support 1. Support Acer Aspire 9810 2. Support TOSHIBA A205 3. Support HP TX1000 Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 125 +++++++++++++++++++++++++++++++----------- 1 file changed, 93 insertions(+), 32 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 171f64192dc8..778853c0de8c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -102,6 +102,7 @@ enum { /* ALC268 models */ enum { ALC268_3ST, + ALC268_TOSHIBA, ALC268_AUTO, ALC268_MODEL_LAST /* last tag */ }; @@ -129,6 +130,7 @@ enum { ALC861VD_6ST_DIG, ALC861VD_LENOVO, ALC861VD_DALLAS, + ALC861VD_HP, ALC861VD_AUTO, ALC861VD_MODEL_LAST, }; @@ -6253,16 +6255,14 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = { }; static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), @@ -6277,7 +6277,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { .put = alc883_mux_enum_put, }, { } /* end */ -}; +}; static struct snd_kcontrol_new alc883_chmode_mixer[] = { { @@ -6490,18 +6490,6 @@ static struct hda_verb alc883_medion_md2_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_acer_aspire_verbs[] = { - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - { } /* end */ -}; - /* toggle speaker-output according to the hp-jack state */ static void alc883_medion_md2_automute(struct hda_codec *codec) { @@ -6576,6 +6564,21 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, alc883_lenovo_101e_ispeaker_automute(codec); } +static struct hda_verb alc883_acer_eapd_verbs[] = { + /* HP Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + { } +}; + /* * generic initialization of ADC, input mixers and output mixers */ @@ -6718,6 +6721,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), @@ -6834,8 +6838,13 @@ static struct alc_config_preset alc883_presets[] = { .input_mux = &alc883_capture_source, }, [ALC883_ACER_ASPIRE] = { - .mixers = { alc883_acer_aspire_mixer}, - .init_verbs = { alc883_init_verbs, alc883_acer_aspire_verbs}, + .mixers = { alc883_acer_aspire_mixer, alc883_chmode_mixer }, + /* On TravelMate laptops, GPIO 0 enables the internal speaker + * and the headphone jack. Turn this on and rely on the + * standard mute methods whenever the user wants to turn + * these outputs off. + */ + .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .dig_out_nid = ALC883_DIGOUT_NID, @@ -6844,9 +6853,7 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_medion_md2_unsol_event, - .init_hook = alc883_medion_md2_automute, - }, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, @@ -8221,6 +8228,12 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { { } }; +static struct hda_verb alc268_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + /* * generic initialization of ADC, input mixers and output mixers */ @@ -8610,6 +8623,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), + SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), {} }; @@ -8627,6 +8641,18 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, }, + [ALC268_TOSHIBA] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + }, }; static int patch_alc268(struct hda_codec *codec) @@ -9916,6 +9942,14 @@ static struct hda_input_mux alc861vd_dallas_capture_source = { }, }; +static struct hda_input_mux alc861vd_hp_capture_source = { + .num_items = 2, + .items = { + { "Front Mic", 0x0 }, + { "ATAPI Mic", 0x1 }, + }, +}; + #define alc861vd_mux_enum_info alc_mux_enum_info #define alc861vd_mux_enum_get alc_mux_enum_get @@ -10117,6 +10151,22 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { { } /* end */ }; +/* Pin assignment: Speaker=0x14, Line-out = 0x15, + * Front Mic=0x18, ATAPI Mic = 0x19, + */ +static struct snd_kcontrol_new alc861vd_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + + { } /* end */ +}; + /* * generic initialization of ADC, input mixers and output mixers */ @@ -10399,6 +10449,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), {} }; @@ -10488,7 +10539,21 @@ static struct alc_config_preset alc861vd_presets[] = { .input_mux = &alc861vd_dallas_capture_source, .unsol_event = alc861vd_dallas_unsol_event, .init_hook = alc861vd_dallas_automute, - }, + }, + [ALC861VD_HP] = { + .mixers = { alc861vd_hp_mixer }, + .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), + .dig_out_nid = ALC861VD_DIGOUT_NID, + .adc_nids = alc861vd_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, + }, }; /* @@ -10849,7 +10914,7 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; const struct hda_input_mux *imux = spec->input_mux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; + static hda_nid_t capture_mixers[2] = { 0x23, 0x22 }; hda_nid_t nid = capture_mixers[adc_idx]; unsigned int *cur_val = &spec->cur_mux[adc_idx]; unsigned int i, idx; @@ -11173,11 +11238,7 @@ static struct hda_verb alc662_auto_init_verbs[] = { /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /*{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},*/ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { } }; -- cgit v1.2.3 From 39c5d41ffef0e176968079f2f84f657e8511cdf9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Aug 2007 16:24:17 +0200 Subject: [ALSA] hda-codec - Add support for Biostar NF61S SE mobo Added the support for Biostar NF61S SE mobo with ALC861VD codec, model=6stack-digout (ALSA bug#3190). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 778853c0de8c..3a0288143109 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10448,6 +10448,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), {} -- cgit v1.2.3 From 983f8ae4067cf0731f19fc6bda3bc3ef200c32e7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Aug 2007 16:44:04 +0200 Subject: [ALSA] hda-codec - Add option texts and descriptions for new Realtek models Added the missing text entries and descriptions for the newly added model values for Realtek codec chips. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3a0288143109..a6fcfbce0c0e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8618,6 +8618,7 @@ static void alc268_auto_init(struct hda_codec *codec) */ static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", [ALC268_AUTO] = "auto", }; @@ -10427,12 +10428,13 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re */ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", - [ALC660VD_3ST_DIG]= "3stack-660-digout", + [ALC660VD_3ST_DIG] = "3stack-660-digout", [ALC861VD_3ST] = "3stack", [ALC861VD_3ST_DIG] = "3stack-digout", [ALC861VD_6ST_DIG] = "6stack-digout", [ALC861VD_LENOVO] = "lenovo", [ALC861VD_DALLAS] = "dallas", + [ALC861VD_HP] = "hp", [ALC861VD_AUTO] = "auto", }; -- cgit v1.2.3 From 2525fdc42fdc4bb943ec2fa5a37e2ae139e1b6d3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Aug 2007 22:18:22 +0200 Subject: [ALSA] hda-intel - Add flush_scheduled_work() in snd_hda_codec_free() Added flush_scheduled_work() in snd_hda_codec_free() to make sure that the all work is gone. Also, optimized the condition to schedule the delayed work in snd_hda_power_down(). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0e923f3f0a80..0b9029436bb4 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -525,6 +525,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) return; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); + flush_scheduled_work(); #endif list_del(&codec->list); codec->bus->caddr_tbl[codec->addr] = NULL; @@ -2223,7 +2224,7 @@ void snd_hda_power_up(struct hda_codec *codec) void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; - if (!codec->power_on) + if (!codec->power_on || codec->power_count) return; if (power_save) schedule_delayed_work(&codec->power_work, -- cgit v1.2.3 From 20a45e8644ef4f5e7dfd727859301c4c581e9489 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Aug 2007 22:20:45 +0200 Subject: [ALSA] hda-codec - Fix Master volume with AD1986A laptop model Use the bind-control for NID 0x1a and 0x1b as Master volume control on AD1986 model=laptop as well as model=laptop-eapd. This will fix the missing output on some devices. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 53cfa0da4964..bc4b797aa97b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -498,13 +498,30 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = { /* laptop model - 2ch only */ static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; +/* master controls both pins 0x1a and 0x1b */ +static struct hda_bind_ctls ad1986a_laptop_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; + +static struct hda_bind_ctls ad1986a_laptop_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; + static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), @@ -532,25 +549,6 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { /* laptop-eapd model - 2ch only */ -/* master controls both pins 0x1a and 0x1b */ -static struct hda_bind_ctls ad1986a_laptop_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0, - }, -}; - -static struct hda_bind_ctls ad1986a_laptop_master_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0, - }, -}; - static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { .num_items = 3, .items = { -- cgit v1.2.3 From 0cb65f2262776e07c2b8ec1121738b97f8941dae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 12:32:45 +0200 Subject: [ALSA] hda-intel - Add position_fix quirk for Dell Precision 390 Dell Precision 390 needs position_fix=1 as default (ALSA bug#3295). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ab698336563c..14bcc108e778 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1642,6 +1642,7 @@ static int azx_dev_free(struct snd_device *device) */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), + SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), {} }; -- cgit v1.2.3 From d273809e2e512d0638d443dce408ac0342ab73cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 14:59:45 +0200 Subject: [ALSA] hda-codec - Add ALC268 acer model Added model=acer for ALC268 codec support. The configuration is: headphone = 0x14, speaker = 0x15 needs hp-jack auto-detection. The same routine as alc262-fujitsu model is used. Also, added the auto-muting routine for ALC268 model=toshiba. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 76 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a6fcfbce0c0e..b47934f87f8c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -103,6 +103,7 @@ enum { enum { ALC268_3ST, ALC268_TOSHIBA, + ALC268_ACER, ALC268_AUTO, ALC268_MODEL_LAST /* last tag */ }; @@ -8234,6 +8235,58 @@ static struct hda_verb alc268_eapd_verbs[] = { { } }; +/* Toshiba specific */ +#define alc268_toshiba_automute alc262_hippo_automute + +static struct hda_verb alc268_toshiba_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* Acer specific */ +#define alc268_acer_bind_master_vol alc262_fujitsu_bind_master_vol +#define alc268_acer_master_sw_put alc262_fujitsu_master_sw_put +#define alc268_acer_automute alc262_fujitsu_automute + +static struct snd_kcontrol_new alc268_acer_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + { } +}; + +static struct hda_verb alc268_acer_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +/* unsolicited event for HP jack sensing */ +static void alc268_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 28) != ALC880_HP_EVENT) + return; + alc268_toshiba_automute(codec); +} + +static void alc268_acer_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 28) != ALC880_HP_EVENT) + return; + alc268_acer_automute(codec, 1); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -8619,12 +8672,15 @@ static void alc268_auto_init(struct hda_codec *codec) static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", [ALC268_AUTO] = "auto", }; static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), {} }; @@ -8644,7 +8700,8 @@ static struct alc_config_preset alc268_presets[] = { }, [ALC268_TOSHIBA] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, .num_dacs = ARRAY_SIZE(alc268_dac_nids), .dac_nids = alc268_dac_nids, .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), @@ -8653,6 +8710,23 @@ static struct alc_config_preset alc268_presets[] = { .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, + .input_mux = &alc268_capture_source, + .unsol_event = alc268_toshiba_unsol_event, + .init_hook = alc268_toshiba_automute, + }, + [ALC268_ACER] = { + .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc268_acer_unsol_event, }, }; -- cgit v1.2.3 From 7debbe51cc001a6deb549999f9d8f53d99c6fd9e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 15:01:03 +0200 Subject: [ALSA] hda-codec - Fix PM on ALC885 Intel Macs Fix power-management on ALC885 Intel Macs. It fixes the problem with power-saving mode, too. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b47934f87f8c..b63d185433f9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5276,6 +5276,20 @@ static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) AC_VERB_SET_GPIO_DATA, gpiostate); } +/* set up GPIO at initialization */ +static void alc885_macpro_init_hook(struct hda_codec *codec) +{ + alc882_gpio_mute(codec, 0, 0); + alc882_gpio_mute(codec, 1, 0); +} + +/* set up GPIO and update auto-muting at initialization */ +static void alc885_imac24_init_hook(struct hda_codec *codec) +{ + alc885_macpro_init_hook(codec); + alc885_imac24_automute(codec); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -5480,6 +5494,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, + .init_hook = alc885_macpro_init_hook, }, [ALC885_IMAC24] = { .mixers = { alc885_imac24_mixer }, @@ -5492,7 +5507,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, .unsol_event = alc885_imac24_unsol_event, - .init_hook = alc885_imac24_automute, + .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer, @@ -5695,11 +5710,6 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); - if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) { - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); - } - spec->stream_name_analog = "ALC882 Analog"; spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; -- cgit v1.2.3 From 6c726dc672d82749e09345a79350838d4558fae4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 15:02:16 +0200 Subject: [ALSA] hda-codec - Remove superfluous code Remove the superfluous code that's actually not used at all. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b63d185433f9..31ff11721b7d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8672,10 +8672,6 @@ static void alc268_auto_init(struct hda_codec *codec) alc268_auto_init_analog_input(codec); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc883_loopbacks alc880_loopbacks -#endif - /* * configuration and preset */ -- cgit v1.2.3 From 676a9b53dcb0843a98f7339a492e42baf4b9a734 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 15:23:35 +0200 Subject: [ALSA] hda-codec - Add unsol_event to ALC883 Acer Aspire Added unsol_event handling to ALC883 Acer Aspire codes. Also, removed unneeded channel-mode mixer control from 2-ch only presets. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 31ff11721b7d..eec1a784386a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6575,18 +6575,41 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, alc883_lenovo_101e_ispeaker_automute(codec); } +/* toggle speaker-output according to the hp-jack state */ +static void alc883_acer_aspire_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + +static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_acer_aspire_automute(codec); +} + static struct hda_verb alc883_acer_eapd_verbs[] = { /* HP Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* eanable EAPD on medion laptop */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } }; @@ -6832,8 +6855,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc883_tagra_automute, }, [ALC883_ACER] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, + .mixers = { alc883_base_mixer }, /* On TravelMate laptops, GPIO 0 enables the internal speaker * and the headphone jack. Turn this on and rely on the * standard mute methods whenever the user wants to turn @@ -6849,12 +6871,7 @@ static struct alc_config_preset alc883_presets[] = { .input_mux = &alc883_capture_source, }, [ALC883_ACER_ASPIRE] = { - .mixers = { alc883_acer_aspire_mixer, alc883_chmode_mixer }, - /* On TravelMate laptops, GPIO 0 enables the internal speaker - * and the headphone jack. Turn this on and rely on the - * standard mute methods whenever the user wants to turn - * these outputs off. - */ + .mixers = { alc883_acer_aspire_mixer }, .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -6864,6 +6881,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, + .unsol_event = alc883_acer_aspire_unsol_event, + .init_hook = alc883_acer_aspire_automute, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -6893,8 +6912,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc883_medion_md2_automute, }, [ALC883_LAPTOP_EAPD] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, + .mixers = { alc883_base_mixer }, .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, -- cgit v1.2.3 From a221e287ab39a0d169809cb79536abd75392c3c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 16:35:33 +0200 Subject: [ALSA] hda-intel - Avoid unnecessary work scheduling Avoid unnecessary work scheduling for power-off. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 10 +++++++--- sound/pci/hda/hda_codec.h | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0b9029436bb4..b1eee9a044fe 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1664,6 +1664,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); codec->power_on = 0; + codec->power_transition = 0; #endif } @@ -2211,7 +2212,7 @@ static void hda_keep_power_on(struct hda_codec *codec) void snd_hda_power_up(struct hda_codec *codec) { codec->power_count++; - if (codec->power_on) + if (codec->power_on || codec->power_transition) return; codec->power_on = 1; @@ -2219,16 +2220,19 @@ void snd_hda_power_up(struct hda_codec *codec) codec->bus->ops.pm_notify(codec); hda_call_codec_resume(codec); cancel_delayed_work(&codec->power_work); + codec->power_transition = 0; } void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; - if (!codec->power_on || codec->power_count) + if (!codec->power_on || codec->power_count || codec->power_transition) return; - if (power_save) + if (power_save) { + codec->power_transition = 1; /* avoid reentrance */ schedule_delayed_work(&codec->power_work, msecs_to_jiffies(power_save * 1000)); + } } int snd_hda_check_amp_list_power(struct hda_codec *codec, diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1ffffaa3a30d..ca157e5100c9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -586,7 +586,8 @@ struct hda_codec { struct snd_hwdep *hwdep; /* assigned hwdep device */ #ifdef CONFIG_SND_HDA_POWER_SAVE - int power_on; /* current (global) power-state */ + unsigned int power_on :1; /* current (global) power-state */ + unsigned int power_transition :1; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ #endif -- cgit v1.2.3 From 64ca1c294c94579af68197d5f4af6911236b5a51 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 17:23:32 +0200 Subject: [ALSA] hda-codec - Add model for MSI m673x Added model=targa-dig for MSI m673x with ALC883 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index eec1a784386a..7466df4767eb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6751,6 +6751,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), -- cgit v1.2.3 From 72e7b0ddf52d334939778fc71e9d013519a3ee8c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 17:33:55 +0200 Subject: [ALSA] hda-codec - Add auto-mute function to Sony VAIO with STAC9872 Added auto-mute function with HP jack to Sony VAIO laptop with STAC9872 codec. The patch taken from ALSA bug#3275. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 47 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e096a48899c8..76ec32a375c0 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2411,6 +2411,7 @@ static struct hda_input_mux vaio_mux = { static struct hda_verb vaio_init[] = { {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ + {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ @@ -2507,6 +2508,49 @@ static struct hda_codec_ops stac9872_patch_ops = { #endif }; +static int stac9872_vaio_init(struct hda_codec *codec) +{ + int err; + + err = stac92xx_init(codec); + if (err < 0) + return err; + if (codec->patch_ops.unsol_event) + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + return 0; +} + +static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) +{ + if (get_pin_presence(codec, 0x0a)) { + stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + } else { + stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + } +} + +static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res) +{ + switch (res >> 26) { + case STAC_HP_EVENT: + stac9872_vaio_hp_detect(codec, res); + break; + } +} + +static struct hda_codec_ops stac9872_vaio_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac9872_vaio_init, + .free = stac92xx_free, + .unsol_event = stac9872_vaio_unsol_event, +#ifdef CONFIG_PM + .resume = stac92xx_resume, +#endif +}; + enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */ CXD9872RD_VAIO, /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */ @@ -2562,6 +2606,7 @@ static int patch_stac9872(struct hda_codec *codec) spec->adc_nids = vaio_adcs; spec->input_mux = &vaio_mux; spec->mux_nids = vaio_mux_nids; + codec->patch_ops = stac9872_vaio_patch_ops; break; case CXD9872AKD_VAIO: @@ -2575,10 +2620,10 @@ static int patch_stac9872(struct hda_codec *codec) spec->adc_nids = vaio_adcs; spec->input_mux = &vaio_mux; spec->mux_nids = vaio_mux_nids; + codec->patch_ops = stac9872_patch_ops; break; } - codec->patch_ops = stac9872_patch_ops; return 0; } -- cgit v1.2.3 From 38baf5ad8b7d24be16a2cf0e4c1d7429aeb4aa45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 17:52:43 +0200 Subject: [ALSA] hda-codec - Fix Toshiba A135 model selection Fixed the double entries in the model presets. Toshib A135 prefers model=lenovo rather than dallas. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7466df4767eb..e4064f997e8c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10544,7 +10544,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS), + /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), -- cgit v1.2.3 From 87350ad0cf05d734309ca40e1524a07cf12190aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 18:19:38 +0200 Subject: [ALSA] hda-codec - Add support for Macbook Pro rev3 Added the support for Macbook Pro rev3 with ALC885 codec chip. The patch taken from ALSA bug#3242. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 145 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e4064f997e8c..0473f2a9c182 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -156,6 +156,7 @@ enum { ALC882_TARGA, ALC882_ASUS_A7J, ALC885_MACPRO, + ALC885_MBP3, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -4895,6 +4896,38 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { { 8, alc882_sixstack_ch8_init }, }; +/* + * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic + */ + +/* + * 2ch mode + */ +static struct hda_verb alc885_mbp_ch2_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc885_mbp_ch6_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } /* end */ +}; + +static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { + { 2, alc885_mbp_ch2_init }, + { 6, alc885_mbp_ch6_init }, +}; + + /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -4925,6 +4958,19 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc885_mbp3_mixer[] = { + HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -5135,6 +5181,66 @@ static struct hda_verb alc882_macpro_init_verbs[] = { { } }; +/* Macbook Pro rev3 */ +static struct hda_verb alc885_mbp3_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + /* iMac 24 mixer. */ static struct snd_kcontrol_new alc885_imac24_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), @@ -5185,6 +5291,27 @@ static void alc885_imac24_unsol_event(struct hda_codec *codec, alc885_imac24_automute(codec); } +static void alc885_mbp3_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); + +} +static void alc885_mbp3_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_mbp3_automute(codec); +} + + static struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -5422,6 +5549,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_ARIMA] = "arima", [ALC882_W2JC] = "w2jc", [ALC885_MACPRO] = "macpro", + [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", }; @@ -5484,6 +5612,20 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mbp_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_mbp3_unsol_event, + .init_hook = alc885_mbp3_automute, + }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, .init_verbs = { alc882_macpro_init_verbs }, @@ -5684,6 +5826,9 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b1000: /* iMac 24 */ board_config = ALC885_IMAC24; break; + case 0x106b2c00: /* Macbook Pro rev3 */ + board_config = ALC885_MBP3; + break; default: printk(KERN_INFO "hda_codec: Unknown model for ALC882, " "trying auto-probe from BIOS...\n"); -- cgit v1.2.3 From 542d7c66201439f98dd44e62a8186ec33a15b1a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Aug 2007 18:57:30 +0200 Subject: [ALSA] hda-codec - Add support for Toshiba Satellite P205 Add model=lenovo for Toshiba Satellite P205 with ALC861VD codec chip. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0473f2a9c182..e82b03a59790 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10694,6 +10694,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), -- cgit v1.2.3 From 6bc9685796529754acd819d9c979227d823c408d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Aug 2007 09:02:12 +0200 Subject: [ALSA] hda-codec - Fix ALC268 acer model ALC268 has different NIDs from ALC262. Acer model should use NID 0x02 and 0x03 instead of 0x0c and 0x0d for the master volume. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e82b03a59790..4a40a056a8c6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8418,7 +8418,16 @@ static struct hda_verb alc268_toshiba_verbs[] = { }; /* Acer specific */ -#define alc268_acer_bind_master_vol alc262_fujitsu_bind_master_vol +/* bind volumes of both NID 0x0c and 0x0d */ +static struct hda_bind_ctls alc268_acer_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; + #define alc268_acer_master_sw_put alc262_fujitsu_master_sw_put #define alc268_acer_automute alc262_fujitsu_automute -- cgit v1.2.3 From 669ba27a6e25251427bde8f4980f62733a8f0c7e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Aug 2007 09:17:36 +0200 Subject: [ALSA] hda-intel - Add probe_mask blacklist Added the black-list of probe_mask option to set the default value for known non-working devices. Currently, Thinkpad *60 and *61 series are set. I'm afraid more will be added to the list in near future... Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 14bcc108e778..3d06eccc9b9c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1653,7 +1653,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) if (fix == POS_FIX_AUTO) { q = snd_pci_quirk_lookup(chip->pci, position_fix_list); if (q) { - snd_printdd(KERN_INFO + printk(KERN_INFO "hda_intel: position_fix set to %d " "for device %04x:%04x\n", q->value, q->subvendor, q->subdevice); @@ -1663,6 +1663,36 @@ static int __devinit check_position_fix(struct azx *chip, int fix) return fix; } +/* + * black-lists for probe_mask + */ +static struct snd_pci_quirk probe_mask_list[] __devinitdata = { + /* Thinkpad often breaks the controller communication when accessing + * to the non-working (or non-existing) modem codec slot. + */ + SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + {} +}; + +static void __devinit check_probe_mask(struct azx *chip) +{ + const struct snd_pci_quirk *q; + + if (probe_mask == -1) { + q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); + if (q) { + printk(KERN_INFO + "hda_intel: probe_mask set to 0x%x " + "for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); + probe_mask = q->value; + } + } +} + + /* * constructor */ @@ -1698,6 +1728,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->msi = enable_msi; chip->position_fix = check_position_fix(chip, position_fix); + check_probe_mask(chip); chip->single_cmd = single_cmd; -- cgit v1.2.3 From 189609ae1e4db898d9a933753348ca19544c5903 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Mon, 20 Aug 2007 11:31:23 +0200 Subject: [ALSA] hda-codec - Add support for Haier W66 1. Support Lenovo 420A (PCI SSID: 0x17aa 0x3bfc) 2. Support Haier W66 (PCI SSID: 0x1991 0x5625) Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 52 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4a40a056a8c6..f558b801c82d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -177,7 +177,8 @@ enum { ALC883_LAPTOP_EAPD, ALC883_LENOVO_101E_2ch, ALC883_LENOVO_NB0763, - ALC888_LENOVO_MS7195_DIG, + ALC888_LENOVO_MS7195_DIG, + ALC883_HAIER_W66, ALC888_6ST_HP, ALC888_3ST_HP, ALC883_AUTO, @@ -6567,6 +6568,19 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = { { } /* end */ }; +static struct hda_verb alc883_haier_w66_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + static struct hda_verb alc888_6st_hp_verbs[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */ @@ -6685,6 +6699,25 @@ static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) alc883_tagra_automute(codec); } +static void alc883_haier_w66_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? 0x80 : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + 0x80, bits); +} + +static void alc883_haier_w66_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_haier_w66_automute(codec); +} + static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) { unsigned int present; @@ -6871,6 +6904,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_LENOVO_101E_2ch] = "lenovo-101e", [ALC883_LENOVO_NB0763] = "lenovo-nb0763", [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", + [ALC883_HAIER_W66] = "haier-w66", [ALC888_6ST_HP] = "6stack-hp", [ALC888_3ST_HP] = "3stack-hp", [ALC883_AUTO] = "auto", @@ -6915,6 +6949,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), + SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), + SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), {} }; @@ -7109,6 +7145,20 @@ static struct alc_config_preset alc883_presets[] = { .input_mux = &alc883_capture_source, .unsol_event = alc883_lenovo_ms7195_unsol_event, .init_hook = alc888_lenovo_ms7195_front_automute, + }, + [ALC883_HAIER_W66] = { + .mixers = { alc883_tagra_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_haier_w66_unsol_event, + .init_hook = alc883_haier_w66_automute, }, [ALC888_6ST_HP] = { .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer }, -- cgit v1.2.3 From d53d7d9e5e6bce747e8b8b2f825db1b32d8f6647 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Aug 2007 15:20:02 +0200 Subject: [ALSA] hda-codec - Add SPDIF support on ALC880 fujitsu model Some Fujitsu laptops have SPDIF output jack (ALSA bug#3009). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f558b801c82d..e67f586ebfbe 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2875,6 +2875,7 @@ static struct alc_config_preset alc880_presets[] = { alc880_beep_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, -- cgit v1.2.3 From 33bf17abf98087d7a6eec9476cd767c6e998fc05 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Aug 2007 11:51:42 +0200 Subject: [ALSA] hda-codec - Add missing capture boost for ALC268 Added missing capture boost controls for ALC268 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e67f586ebfbe..db29ebea20b5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8451,6 +8451,9 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), { } }; @@ -8493,6 +8496,9 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { .put = alc268_acer_master_sw_put, .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), }, + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), { } }; -- cgit v1.2.3 From 1fcaee6ee212fc214c1327d788afa10899c22e3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Aug 2007 00:01:09 +0200 Subject: [ALSA] hda-intel - Fix compile with gcc-3.x gcc-3.x doesn't like forward inlining: CC [M] sound/pci/hda/hda_codec.o sound/pci/hda/hda_codec.c: In function 'snd_hda_codec_free': sound/pci/hda/hda_codec.c:517: sorry, unimplemented: inlining failed in call to 'free_hda_cache': function body not available sound/pci/hda/hda_codec.c:534: sorry, unimplemented: called from here sound/pci/hda/hda_codec.c:517: sorry, unimplemented: inlining failed in call to 'free_hda_cache': function body not available sound/pci/hda/hda_codec.c:535: sorry, unimplemented: called from here Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b1eee9a044fe..46d4253642d7 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -514,7 +514,7 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); -static inline void free_hda_cache(struct hda_cache_rec *cache); +static void free_hda_cache(struct hda_cache_rec *cache); /* * codec destructor @@ -707,7 +707,7 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache, cache->record_size = record_size; } -static inline void free_hda_cache(struct hda_cache_rec *cache) +static void free_hda_cache(struct hda_cache_rec *cache) { kfree(cache->buffer); } -- cgit v1.2.3 From 0724ea2a85a804e151d960359b599ae8a7c1cad1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Aug 2007 00:31:43 +0200 Subject: [ALSA] hda-codec - Fix mater mixer switch of ALC262 sony-amd model Fixed the master mixer switch of ALC272 sony-amd model. It used a simple bind-control, but it resulted in unexpected unmute of speaker output. Now the control checks the HP jack state apropriately, just like fujitsu model. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 48 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index db29ebea20b5..4cbd0e6e849d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7453,18 +7453,46 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { { } /* end */ }; -static struct hda_bind_ctls alc262_sony_bind_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - 0, - }, -}; +/* bind hp and internal speaker mute (with plug check) */ +static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + /* change hp mute */ + change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) { + /* change speaker according to HP jack state */ + struct alc_spec *spec = codec->spec; + unsigned int mute; + if (spec->jack_present) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, + HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } + return change; +} static struct snd_kcontrol_new alc262_sony_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_SW("Front Playback Switch", &alc262_sony_bind_sw), + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), -- cgit v1.2.3 From 889c43955115ea7412d71335e3ceff6bad118dce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Aug 2007 18:56:52 +0200 Subject: [ALSA] hda-codec - Fix ALC268 unsol event The unsol event of ALC268 is in the standard bit 26. Also, fixed the Acer master controls, and added Extensa 5210 to the quirk list. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 55 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4cbd0e6e849d..b108ea3d99b3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8500,7 +8500,7 @@ static struct hda_verb alc268_toshiba_verbs[] = { }; /* Acer specific */ -/* bind volumes of both NID 0x0c and 0x0d */ +/* bind volumes of both NID 0x02 and 0x03 */ static struct hda_bind_ctls alc268_acer_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { @@ -8510,8 +8510,46 @@ static struct hda_bind_ctls alc268_acer_bind_master_vol = { }, }; -#define alc268_acer_master_sw_put alc262_fujitsu_master_sw_put -#define alc268_acer_automute alc262_fujitsu_automute +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc268_acer_automute(struct hda_codec *codec, int force) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + if (force || !spec->sense_updated) { + unsigned int present; + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + spec->sense_updated = 1; + } + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} + + +/* bind hp and internal speaker mute (with plug check) */ +static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc268_acer_automute(codec, 0); + return change; +} static struct snd_kcontrol_new alc268_acer_mixer[] = { /* output mixer control */ @@ -8542,7 +8580,7 @@ static struct hda_verb alc268_acer_verbs[] = { static void alc268_toshiba_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 28) != ALC880_HP_EVENT) + if ((res >> 26) != ALC880_HP_EVENT) return; alc268_toshiba_automute(codec); } @@ -8550,11 +8588,16 @@ static void alc268_toshiba_unsol_event(struct hda_codec *codec, static void alc268_acer_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 28) != ALC880_HP_EVENT) + if ((res >> 26) != ALC880_HP_EVENT) return; alc268_acer_automute(codec, 1); } +static void alc268_acer_init_hook(struct hda_codec *codec) +{ + alc268_acer_automute(codec, 1); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -8945,6 +8988,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), {} }; @@ -8991,6 +9035,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, }, }; -- cgit v1.2.3 From dfe495d0a51e20325b51760f34a2f53bfe1f3b52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Aug 2007 19:04:28 +0200 Subject: [ALSA] hda-codec - Fix Dell laptops support with STAC codecs Fixed Dell laptops support with STAC92xx codecs. Many pin-config models are introduced. See ALSA-Configuration.txt for details. The patch taken from ALSA bug#3319, originally by Jorg Prante: https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3319 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 345 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 313 insertions(+), 32 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 76ec32a375c0..adca2854e50b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -39,11 +39,22 @@ enum { STAC_REF, + STAC_9200_DELL_D21, + STAC_9200_DELL_D22, + STAC_9200_DELL_D23, + STAC_9200_DELL_M21, + STAC_9200_DELL_M22, + STAC_9200_DELL_M23, + STAC_9200_DELL_M24, + STAC_9200_DELL_M25, + STAC_9200_DELL_M26, + STAC_9200_DELL_M27, STAC_9200_MODELS }; enum { STAC_9205_REF, + STAC_9205_DELL_M42, STAC_9205_DELL_M43, STAC_9205_DELL_M44, STAC_9205_M43xx, @@ -62,19 +73,22 @@ enum { STAC_D945_REF, STAC_D945GTP3, STAC_D945GTP5, - STAC_922X_DELL, STAC_INTEL_MAC_V1, STAC_INTEL_MAC_V2, STAC_INTEL_MAC_V3, STAC_INTEL_MAC_V4, STAC_INTEL_MAC_V5, - /* for backward compitability */ + /* for backward compatibility */ STAC_MACMINI, STAC_MACBOOK, STAC_MACBOOK_PRO_V1, STAC_MACBOOK_PRO_V2, STAC_IMAC_INTEL, STAC_IMAC_INTEL_20, + STAC_922X_DELL_D81, + STAC_922X_DELL_D82, + STAC_922X_DELL_M81, + STAC_922X_DELL_M82, STAC_922X_MODELS }; @@ -456,12 +470,144 @@ static unsigned int ref9200_pin_configs[8] = { 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; +/* + STAC 9200 pin configs for + 102801A8 + 102801DE + 102801E8 +*/ +static unsigned int dell9200_d21_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140, + 0x01813122, 0x02214030, 0x01014010, 0x02a19020, +}; + +/* + STAC 9200 pin configs for + 102801C0 + 102801C1 +*/ +static unsigned int dell9200_d22_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x02a19021, 0x90100140, + 0x400001f2, 0x0221401f, 0x01014010, 0x01813020, +}; + +/* + STAC 9200 pin configs for + 102801C4 (Dell Dimension E310) + 102801C5 + 102801C7 + 102801D9 + 102801DA + 102801E3 +*/ +static unsigned int dell9200_d23_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140, + 0x400001f2, 0x0221401f, 0x01014010, 0x01813020, +}; + + +/* + STAC 9200-32 pin configs for + 102801B5 (Dell Inspiron 630m) + 102801D8 (Dell Inspiron 640m) +*/ +static unsigned int dell9200_m21_pin_configs[8] = { + 0x40c003fa, 0x03441340, 0x03a11020, 0x401003fc, + 0x403003fd, 0x0321121f, 0x0321121f, 0x408003fb, +}; + +/* + STAC 9200-32 pin configs for + 102801C2 (Dell Latitude D620) + 102801C8 + 102801CC (Dell Latitude D820) + 102801D4 + 102801D6 +*/ +static unsigned int dell9200_m22_pin_configs[8] = { + 0x40c003fa, 0x0144131f, 0x03A11020, 0x401003fb, + 0x40f000fc, 0x0321121f, 0x90170310, 0x90a70321, +}; + +/* + STAC 9200-32 pin configs for + 102801CE (Dell XPS M1710) + 102801CF (Dell Precision M90) +*/ +static unsigned int dell9200_m23_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, + 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, +}; + +/* + STAC 9200-32 pin configs for + 102801C9 + 102801CA + 102801CB (Dell Latitude 120L) + 102801D3 +*/ +static unsigned int dell9200_m24_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x03a11020, 0x401003fd, + 0x403003fe, 0x0321121f, 0x90170310, 0x408003fc, +}; + +/* + STAC 9200-32 pin configs for + 102801BD (Dell Inspiron E1505n) + 102801EE + 102801EF +*/ +static unsigned int dell9200_m25_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x04a11020, 0x401003fc, + 0x403003fd, 0x0421121f, 0x90170310, 0x408003fb, +}; + +/* + STAC 9200-32 pin configs for + 102801F5 (Dell Inspiron 1501) + 102801F6 +*/ +static unsigned int dell9200_m26_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x04a11020, 0x401003fd, + 0x403003fe, 0x0421121f, 0x90170310, 0x408003fc, +}; + +/* + STAC 9200-32 + 102801CD (Dell Inspiron E1705/9400) +*/ +static unsigned int dell9200_m27_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x04a11020, 0x90170310, + 0x40f003fc, 0x0421121f, 0x90170310, 0x408003fb, +}; + + static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_REF] = ref9200_pin_configs, + [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, + [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, + [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, + [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, + [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, + [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, + [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, + [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, + [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, + [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, }; static const char *stac9200_models[STAC_9200_MODELS] = { [STAC_REF] = "ref", + [STAC_9200_DELL_D21] = "dell-d21", + [STAC_9200_DELL_D22] = "dell-d22", + [STAC_9200_DELL_D23] = "dell-d23", + [STAC_9200_DELL_M21] = "dell-m21", + [STAC_9200_DELL_M22] = "dell-m22", + [STAC_9200_DELL_M23] = "dell-m23", + [STAC_9200_DELL_M24] = "dell-m24", + [STAC_9200_DELL_M25] = "dell-m25", + [STAC_9200_DELL_M26] = "dell-m26", + [STAC_9200_DELL_M27] = "dell-m27", }; static struct snd_pci_quirk stac9200_cfg_tbl[] = { @@ -469,27 +615,64 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), /* Dell laptops have BIOS problem */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8, + "unknown Dell", STAC_9200_DELL_D21), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, - "Dell Inspiron 630m", STAC_REF), + "Dell Inspiron 630m", STAC_9200_DELL_M21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd, + "Dell Inspiron E1505n", STAC_9200_DELL_M25), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0, + "unknown Dell", STAC_9200_DELL_D22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1, + "unknown Dell", STAC_9200_DELL_D22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, - "Dell Latitude D620", STAC_REF), + "Dell Latitude D620", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8, + "unknown Dell", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9, + "unknown Dell", STAC_9200_DELL_M24), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca, + "unknown Dell", STAC_9200_DELL_M24), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, - "Dell Latitude 120L", STAC_REF), + "Dell Latitude 120L", STAC_9200_DELL_M24), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, - "Dell Latitude D820", STAC_REF), + "Dell Latitude D820", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, - "Dell Inspiron E1705/9400", STAC_REF), + "Dell Inspiron E1705/9400", STAC_9200_DELL_M27), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, - "Dell XPS M1710", STAC_REF), + "Dell XPS M1710", STAC_9200_DELL_M23), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf, - "Dell Precision M90", STAC_REF), + "Dell Precision M90", STAC_9200_DELL_M23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3, + "unknown Dell", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4, + "unknown Dell", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6, - "unknown Dell", STAC_REF), + "unknown Dell", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8, - "Dell Inspiron 640m", STAC_REF), + "Dell Inspiron 640m", STAC_9200_DELL_M21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de, + "unknown Dell", STAC_9200_DELL_D21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8, + "unknown Dell", STAC_9200_DELL_D21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee, + "unknown Dell", STAC_9200_DELL_M25), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef, + "unknown Dell", STAC_9200_DELL_M25), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5, - "Dell Inspiron 1501", STAC_REF), - + "Dell Inspiron 1501", STAC_9200_DELL_M26), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6, + "unknown Dell", STAC_9200_DELL_M26), /* Panasonic */ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), @@ -548,6 +731,51 @@ static unsigned int ref922x_pin_configs[10] = { 0x40000100, 0x40000100, }; +/* + STAC 922X pin configs for + 102801A7 + 102801AB + 102801A9 + 102801D1 + 102801D2 +*/ +static unsigned int dell_922x_d81_pin_configs[10] = { + 0x02214030, 0x01a19021, 0x01111012, 0x01114010, + 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, + 0x01813122, 0x400001f2, +}; + +/* + STAC 922X pin configs for + 102801AC + 102801D0 +*/ +static unsigned int dell_922x_d82_pin_configs[10] = { + 0x02214030, 0x01a19021, 0x01111012, 0x01114010, + 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, + 0x01813122, 0x400001f1, +}; + +/* + STAC 922X pin configs for + 102801BF +*/ +static unsigned int dell_922x_m81_pin_configs[10] = { + 0x0321101f, 0x01112024, 0x01111222, 0x91174220, + 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, + 0x40C003f1, 0x405003f0, +}; + +/* + STAC 9221 A1 pin configs for + 102801D7 (Dell XPS M1210) +*/ +static unsigned int dell_922x_m82_pin_configs[10] = { + 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, + 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, + 0x508003f3, 0x405003f4, +}; + static unsigned int d945gtp3_pin_configs[10] = { 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, 0x40000100, 0x40000100, 0x40000100, 0x40000100, @@ -590,48 +818,49 @@ static unsigned int intel_mac_v5_pin_configs[10] = { 0x400000fc, 0x400000fb, }; -static unsigned int stac922x_dell_pin_configs[10] = { - 0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310, - 0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2, - 0x50a003f3, 0x405003f4 -}; static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_D945_REF] = ref922x_pin_configs, [STAC_D945GTP3] = d945gtp3_pin_configs, [STAC_D945GTP5] = d945gtp5_pin_configs, - [STAC_922X_DELL] = stac922x_dell_pin_configs, [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, - /* for backward compitability */ + /* for backward compatibility */ [STAC_MACMINI] = intel_mac_v3_pin_configs, [STAC_MACBOOK] = intel_mac_v5_pin_configs, [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, + [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, + [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, + [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, + [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, }; static const char *stac922x_models[STAC_922X_MODELS] = { [STAC_D945_REF] = "ref", [STAC_D945GTP5] = "5stack", [STAC_D945GTP3] = "3stack", - [STAC_922X_DELL] = "dell", [STAC_INTEL_MAC_V1] = "intel-mac-v1", [STAC_INTEL_MAC_V2] = "intel-mac-v2", [STAC_INTEL_MAC_V3] = "intel-mac-v3", [STAC_INTEL_MAC_V4] = "intel-mac-v4", [STAC_INTEL_MAC_V5] = "intel-mac-v5", - /* for backward compitability */ + /* for backward compatibility */ [STAC_MACMINI] = "macmini", [STAC_MACBOOK] = "macbook", [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", [STAC_MACBOOK_PRO_V2] = "macbook-pro", [STAC_IMAC_INTEL] = "imac-intel", [STAC_IMAC_INTEL_20] = "imac-intel-20", + [STAC_922X_DELL_D81] = "dell-d81", + [STAC_922X_DELL_D82] = "dell-d82", + [STAC_922X_DELL_M81] = "dell-m81", + [STAC_922X_DELL_M82] = "dell-m82", }; static struct snd_pci_quirk stac922x_cfg_tbl[] = { @@ -695,9 +924,25 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = { /* Apple Mac Mini (early 2006) */ SND_PCI_QUIRK(0x8384, 0x7680, "Mac Mini", STAC_INTEL_MAC_V3), - /* Dell */ - SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL), - + /* Dell systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac, + "unknown Dell", STAC_922X_DELL_D82), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf, + "unknown Dell", STAC_922X_DELL_M81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0, + "unknown Dell", STAC_922X_DELL_D82), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, + "Dell XPS M1210", STAC_922X_DELL_M82), {} /* terminator */ }; @@ -768,7 +1013,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), /* Dell 3 stack systems */ - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell E520", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), /* 965 based 5 stack systems */ @@ -790,28 +1035,54 @@ static unsigned int ref9205_pin_configs[12] = { 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 }; -static unsigned int dell_m43_9205_pin_configs[12] = { +/* + STAC 9205 pin configs for + 102801F1 + 102801F2 + 102801FC + 102801FD + 10280204 + 1028021F +*/ +static unsigned int dell_9205_m42_pin_configs[12] = { + 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, + 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, + 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, +}; + +/* + STAC 9205 pin configs for + 102801F9 + 102801FA + 102801FE + 102801FF (Dell Precision M4300) + 10280206 + 10280200 + 10280201 +*/ +static unsigned int dell_9205_m43_pin_configs[12] = { 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, }; -static unsigned int dell_m44_9205_pin_configs[12] = { +static unsigned int dell_9205_m44_pin_configs[12] = { 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, }; - static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { [STAC_9205_REF] = ref9205_pin_configs, - [STAC_9205_DELL_M43] = dell_m43_9205_pin_configs, - [STAC_9205_DELL_M44] = dell_m44_9205_pin_configs, + [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, + [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, + [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, [STAC_9205_M43xx] = NULL, }; static const char *stac9205_models[STAC_9205_MODELS] = { [STAC_9205_REF] = "ref", + [STAC_9205_DELL_M42] = "dell-m42", [STAC_9205_DELL_M43] = "dell-m43", [STAC_9205_DELL_M44] = "dell-m44", }; @@ -820,16 +1091,24 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, "Dell Precision", STAC_9205_M43xx), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe, "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, - "Dell Precision", STAC_9205_DELL_M43), + "Dell Precision M4300", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, @@ -840,6 +1119,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { "Dell Inspiron", STAC_9205_DELL_M44), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, + "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, "Dell Inspiron", STAC_9205_DELL_M44), {} /* terminator */ -- cgit v1.2.3 From 776e184e8082a4ec9bf4fe18b11dae6dc4e43d1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Aug 2007 15:07:11 +0200 Subject: [ALSA] hda-codec - Add Mic Boost control with auto-configuration Some codecs need Mic Boost mixer controls for obtaining a proper recording level, but the auto-configuration doesn't create them. This patch adds the creation of mic-boost controls on corresponding codecs. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 68 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 8 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b108ea3d99b3..b3062afc481c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5782,6 +5782,32 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) } } +/* add mic boosts if needed */ +static int alc_auto_add_mic_boost(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + hda_nid_t nid; + + nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; + if (nid) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; + if (nid) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Front Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + return 0; +} + /* almost identical with ALC880 parser... */ static int alc882_parse_auto_config(struct hda_codec *codec) { @@ -5790,10 +5816,17 @@ static int alc882_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc882_auto_init_verbs; - return err; + else if (!err) + return 0; /* no config found */ + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + /* hack - override the init verbs */ + spec->init_verbs[0] = alc882_auto_init_verbs; + + return 1; /* config found */ } /* additional initialization for auto-configuration model */ @@ -7270,12 +7303,19 @@ static int alc883_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc883_auto_init_verbs; + else if (!err) + return 0; /* no config found */ + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + /* hack - override the init verbs */ + spec->init_verbs[0] = alc883_auto_init_verbs; spec->mixers[spec->num_mixers] = alc883_capture_mixer; spec->num_mixers++; - return err; + + return 1; /* config found */ } /* additional initialization for auto-configuration model */ @@ -8184,6 +8224,10 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -8957,6 +9001,10 @@ static int alc268_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -11173,6 +11221,10 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } -- cgit v1.2.3 From accbe4988c5cf3dc86f0a042396163ed279536a6 Mon Sep 17 00:00:00 2001 From: zhejiang Date: Fri, 31 Aug 2007 12:36:05 +0200 Subject: [ALSA] hda-codec - Fix capture on ALC262 HP machines Fix the index for Front Mic capture source on ALC262 HP machines. Also, added the new capture source list for HP BPC DC7000 series to work properly. From: zhejiang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b3062afc481c..3557865dde38 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7746,13 +7746,23 @@ static struct hda_input_mux alc262_HP_capture_source = { .num_items = 5, .items = { { "Mic", 0x0 }, - { "Front Mic", 0x3 }, + { "Front Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, { "AUX IN", 0x6 }, }, }; +static struct hda_input_mux alc262_HP_D7000_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + }, +}; + /* mute/unmute internal speaker according to the hp jack and mute state */ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) { @@ -8357,7 +8367,7 @@ static struct alc_config_preset alc262_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, + .input_mux = &alc262_HP_D7000_capture_source, }, [ALC262_HP_BPC_D7000_WL] = { .mixers = { alc262_HP_BPC_WildWest_mixer, @@ -8368,7 +8378,7 @@ static struct alc_config_preset alc262_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, + .input_mux = &alc262_HP_D7000_capture_source, }, [ALC262_BENQ_ED8] = { .mixers = { alc262_base_mixer }, -- cgit v1.2.3 From ca7c5a8b4b4f61087851bb440118e62a688c1688 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 31 Aug 2007 12:52:19 +0200 Subject: [ALSA] hda-codec - code cleanups in patch_sigmatel.c Clean up the mixer entries for Input Source using a macro. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 65 +++++++++++------------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index adca2854e50b..98144f93dff9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -335,17 +335,21 @@ static struct hda_verb stac9205_core_init[] = { {} }; +#define STAC_INPUT_SOURCE \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Input Source", \ + .count = 1, \ + .info = stac92xx_mux_enum_info, \ + .get = stac92xx_mux_enum_get, \ + .put = stac92xx_mux_enum_put, \ + } + + static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), @@ -353,14 +357,7 @@ static struct snd_kcontrol_new stac9200_mixer[] = { }; static struct snd_kcontrol_new stac925x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), @@ -369,14 +366,7 @@ static struct snd_kcontrol_new stac925x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac922x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), @@ -385,28 +375,14 @@ static struct snd_kcontrol_new stac922x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac9227_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), { } /* end */ }; static struct snd_kcontrol_new stac927x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -422,14 +398,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { .get = stac92xx_dmux_enum_get, .put = stac92xx_dmux_enum_put, }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE, HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), -- cgit v1.2.3 From dc81bed127a93e20d2100624273a27369738ffc7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Sep 2007 09:36:36 +0200 Subject: [ALSA] hda-codec - Fix wrong pin-setup at resume of STAC codecs The resume procedure for STAC codecs overrides the cached values and results in the wrong (reset) PIN state. The patch gets rid of the overriding part and simplifies the resume. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 98144f93dff9..39187828503d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2061,9 +2061,9 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, unsigned int event) { if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event)); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | event)); } static int stac92xx_init(struct hda_codec *codec) @@ -2236,10 +2236,19 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) #ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { + struct sigmatel_spec *spec = codec->spec; + stac92xx_set_config_regs(codec); - stac92xx_init(codec); + snd_hda_sequence_write(codec, spec->init); + if (spec->gpio_mute) { + stac922x_gpio_mute(codec, 0, 0); + stac922x_gpio_mute(codec, 1, 0); + } snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); + /* invoke unsolicited event to reset the HP state */ + if (spec->hp_detect) + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 0; } #endif -- cgit v1.2.3 From c480f79bdca58923e605ff5e4698cfe1779bae70 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Sep 2007 09:43:38 +0200 Subject: [ALSA] hda-codec - Avoid zero NID in line_out_pins[] of STAC codecs The STAC codes adds line_out_pins[] for shared mic/line-inputs accordingly. But, the current code may give a hole with NID=0 in some setting, which results in an error at probe. This patch fixes the problem. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 39187828503d..b4a1d73b5721 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1479,7 +1479,8 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf case 3: /* add line-in as side */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { - cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } @@ -1487,12 +1488,14 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf case 2: /* add line-in as clfe and mic as side */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { - cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { - cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } @@ -1500,12 +1503,14 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf case 1: /* add line-in as surr and mic as clfe */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { - cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { - cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } -- cgit v1.2.3 From 2e4924628ad957f702631a7a049c586a780f00f8 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 3 Sep 2007 15:26:57 +0200 Subject: [ALSA] hda-intel - fix a race in dynamic power managment codec->power_transition is supposed to be true while codec is going to be shut off if in the mean time somebody calls snd_hda_power_up, hda_power_work will not shut down the codec, but nether will clear codec->power_transition, thus it stays on forever. Fix this. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 46d4253642d7..08104e2a3e99 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2195,8 +2195,10 @@ static void hda_power_work(struct work_struct *work) struct hda_codec *codec = container_of(work, struct hda_codec, power_work.work); - if (!codec->power_on || codec->power_count) + if (!codec->power_on || codec->power_count) { + codec->power_transition = 0; return; + } hda_call_codec_suspend(codec); if (codec->bus->ops.pm_notify) -- cgit v1.2.3 From d804ad9258c1460916a5e5854655a0dc543fd8a5 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 3 Sep 2007 15:28:04 +0200 Subject: [ALSA] hda-intel - Fix resume logic, when dynamic power managment is on Comment in hda_intel.c states that 'the explicit resume is needed only when POWER_SAVE isn't set', but this is not true. There is no code that will automaticly power up the codec on resume, but only code that powers it up when user accesses it. So if user leaves a sound playing, codec will not be powered To fix that I check if there are any codecs that should be powered codec->power_count, and if so I power them up together with main controller. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 16 +++++++++++++--- sound/pci/hda/hda_codec.h | 4 ++++ sound/pci/hda/hda_intel.c | 8 ++++---- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 08104e2a3e99..e594de0b153e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2787,7 +2787,6 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) return 0; } -#ifndef CONFIG_SND_HDA_POWER_SAVE /** * snd_hda_resume - resume the codecs * @bus: the HDA bus @@ -2803,10 +2802,21 @@ int snd_hda_resume(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - hda_call_codec_resume(codec); + if (snd_hda_codec_needs_resume(codec)) + hda_call_codec_resume(codec); } return 0; } -#endif /* !CONFIG_SND_HDA_POWER_SAVE */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +int snd_hda_codecs_inuse(struct hda_bus *bus) +{ + struct hda_codec *codec; + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; +} +#endif #endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ca157e5100c9..2bce925d84ef 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -686,9 +686,13 @@ int snd_hda_resume(struct hda_bus *bus); #ifdef CONFIG_SND_HDA_POWER_SAVE void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); +#define snd_hda_codec_needs_resume(codec) codec->power_count +int snd_hda_codecs_inuse(struct hda_bus *bus); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} +#define snd_hda_codec_needs_resume(codec) 1 +#define snd_hda_codecs_inuse(bus) 1 #endif #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3d06eccc9b9c..72fd34538994 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1586,11 +1586,11 @@ static int azx_resume(struct pci_dev *pci) if (azx_acquire_irq(chip, 1) < 0) return -EIO; azx_init_pci(chip); -#ifndef CONFIG_SND_HDA_POWER_SAVE - /* the explicit resume is needed only when POWER_SAVE isn't set */ - azx_init_chip(chip); + + if (snd_hda_codecs_inuse(chip->bus)) + azx_init_chip(chip); + snd_hda_resume(chip->bus); -#endif snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } -- cgit v1.2.3 From 0fb87bb474f978446786263deff6263284e6e011 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 3 Sep 2007 15:29:04 +0200 Subject: [ALSA] hda-codec - add support for swapping center/LFE channels to STAC codecs Center/LFE channels are located on same jack, so it can be usefull to swap them. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 76 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b4a1d73b5721..297f74019279 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -146,6 +146,7 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; + unsigned int clfe_swap; struct hda_pcm pcm_rec[2]; /* PCM information */ @@ -1406,6 +1407,36 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 1; } +#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info + +static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = spec->clfe_swap; + return 0; +} + +static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value & 0xff; + + if (spec->clfe_swap == ucontrol->value.integer.value[0]) + return 0; + + spec->clfe_swap = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + spec->clfe_swap ? 0x4 : 0x0); + + return 1; +} + #define STAC_CODEC_IO_SWITCH(xname, xpval) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -1416,17 +1447,28 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ .private_value = xpval, \ } +#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = 0, \ + .info = stac92xx_clfe_switch_info, \ + .get = stac92xx_clfe_switch_get, \ + .put = stac92xx_clfe_switch_put, \ + .private_value = xpval, \ + } enum { STAC_CTL_WIDGET_VOL, STAC_CTL_WIDGET_MUTE, STAC_CTL_WIDGET_IO_SWITCH, + STAC_CTL_WIDGET_CLFE_SWITCH }; static struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), STAC_CODEC_IO_SWITCH(NULL, 0), + STAC_CODEC_CLFE_SWITCH(NULL, 0), }; /* add dynamic controls */ @@ -1620,7 +1662,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_ } /* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, +static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static const char *chname[4] = { @@ -1629,6 +1671,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, hda_nid_t nid; int i, err; + struct sigmatel_spec *spec = codec->spec; + unsigned int wid_caps; + + for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; @@ -1643,6 +1689,18 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, err = create_controls(spec, "LFE", nid, 2); if (err < 0) return err; + + wid_caps = get_wcaps(codec, nid); + + if (wid_caps & AC_WCAP_LR_SWAP) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_CLFE_SWITCH, + "Swap Center/LFE Playback Switch", nid); + + if (err < 0) + return err; + } + } else { err = create_controls(spec, chname[i], nid, 3); if (err < 0) @@ -1895,9 +1953,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) return err; - if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) + err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); + + if (err < 0) return err; if (spec->num_dmics > 0) -- cgit v1.2.3 From 5f10c4a9a0c02597206fe2f027026ee25d3e07ad Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 3 Sep 2007 15:29:37 +0200 Subject: [ALSA] hda-codec - add support for analog loopback to STAC9204/9205/922x/927x The analog loopback routes the sound just before it enters ADC0 to output of DAC0. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 297f74019279..c94775c8a0bf 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -147,6 +147,7 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; unsigned int clfe_swap; + unsigned int aloopback; struct hda_pcm pcm_rec[2]; /* PCM information */ @@ -296,6 +297,49 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); } +#define stac92xx_aloopback_info snd_ctl_boolean_mono_info + +static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = spec->aloopback; + return 0; +} + +static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int dac_mode; + + if (spec->aloopback == ucontrol->value.integer.value[0]) + return 0; + + spec->aloopback = ucontrol->value.integer.value[0]; + + + dac_mode = snd_hda_codec_read(codec, codec->afg, 0, + kcontrol->private_value & 0xFFFF, 0x0); + + if (spec->aloopback) { + snd_hda_power_up(codec); + dac_mode |= 0x40; + } else { + snd_hda_power_down(codec); + dac_mode &= ~0x40; + } + + snd_hda_codec_write_cache(codec, codec->afg, 0, + kcontrol->private_value >> 16, dac_mode); + + return 1; +} + + static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -346,6 +390,17 @@ static struct hda_verb stac9205_core_init[] = { .put = stac92xx_mux_enum_put, \ } +#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Analog Loopback", \ + .count = 1, \ + .info = stac92xx_aloopback_info, \ + .get = stac92xx_aloopback_get, \ + .put = stac92xx_aloopback_put, \ + .private_value = verb_read | (verb_write << 16), \ + } + static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), @@ -377,6 +432,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac9227_mixer[] = { STAC_INPUT_SOURCE, + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), { } /* end */ @@ -384,6 +440,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = { static struct snd_kcontrol_new stac927x_mixer[] = { STAC_INPUT_SOURCE, + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -400,6 +457,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { .put = stac92xx_dmux_enum_put, }, STAC_INPUT_SOURCE, + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), -- cgit v1.2.3 From 6e6b88ffea81d7bc5c5da0b8433b4a21131ae340 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 3 Sep 2007 15:30:26 +0200 Subject: [ALSA] hda-codec - make volume knob, the master volume for sigmatel codecs VolumeKnob is present on most sigmatel codecs, it allows to decrease volume of all DACs at once, it is a kind of post-procesing volume. Note that all output amps of sigmatel only decrease volume, and all input amps only increase volume. Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c94775c8a0bf..a2b1dd54e2ef 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -339,6 +339,39 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, return 1; } +static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 127; + return 0; +} + +static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = kcontrol->private_value; + return 0; +} + +static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + if (kcontrol->private_value == ucontrol->value.integer.value[0]) + return 0; + + kcontrol->private_value = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, 0x24, 0, + AC_VERB_SET_VOLUME_KNOB_CONTROL, + kcontrol->private_value | 0x80); + return 1; +} + static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ @@ -401,6 +434,17 @@ static struct hda_verb stac9205_core_init[] = { .private_value = verb_read | (verb_write << 16), \ } +#define STAC_VOLKNOB \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Volume", \ + .count = 1, \ + .info = stac92xx_volknob_info, \ + .get = stac92xx_volknob_get, \ + .put = stac92xx_volknob_put, \ + .private_value = 127, \ + } + static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), @@ -423,6 +467,7 @@ static struct snd_kcontrol_new stac925x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac922x_mixer[] = { STAC_INPUT_SOURCE, + STAC_VOLKNOB, HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), @@ -432,6 +477,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac9227_mixer[] = { STAC_INPUT_SOURCE, + STAC_VOLKNOB, STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -440,6 +486,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = { static struct snd_kcontrol_new stac927x_mixer[] = { STAC_INPUT_SOURCE, + STAC_VOLKNOB, STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), @@ -458,6 +505,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { }, STAC_INPUT_SOURCE, STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), + STAC_VOLKNOB, HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), -- cgit v1.2.3 From 9e05b7a3d936ac5eb6c10291b69aee0af1ad03fb Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Mon, 3 Sep 2007 15:31:02 +0200 Subject: [ALSA] hda-codec - Fix support for sigmatel codecs that have 2 or more ADCs 1) Create seperate mixer controls for each ADC 2) Make number of substreams of capture PCM device be equal to number of ADCs Signed-off-by: Maxim Levitsky Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 97 +++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 40 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a2b1dd54e2ef..6dffa54e2da1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -413,11 +413,11 @@ static struct hda_verb stac9205_core_init[] = { {} }; -#define STAC_INPUT_SOURCE \ +#define STAC_INPUT_SOURCE(cnt) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = "Input Source", \ - .count = 1, \ + .count = cnt, \ .info = stac92xx_mux_enum_info, \ .get = stac92xx_mux_enum_get, \ .put = stac92xx_mux_enum_put, \ @@ -449,7 +449,7 @@ static struct hda_verb stac9205_core_init[] = { static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), - STAC_INPUT_SOURCE, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), @@ -457,58 +457,68 @@ static struct snd_kcontrol_new stac9200_mixer[] = { }; static struct snd_kcontrol_new stac925x_mixer[] = { - STAC_INPUT_SOURCE, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), { } /* end */ }; -/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac922x_mixer[] = { - STAC_INPUT_SOURCE, +static struct snd_kcontrol_new stac9205_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Input Source", + .count = 1, + .info = stac92xx_dmux_enum_info, + .get = stac92xx_dmux_enum_get, + .put = stac92xx_dmux_enum_put, + }, + STAC_INPUT_SOURCE(2), + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), STAC_VOLKNOB, - HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT), + { } /* end */ }; /* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac9227_mixer[] = { - STAC_INPUT_SOURCE, +static struct snd_kcontrol_new stac922x_mixer[] = { + STAC_INPUT_SOURCE(2), STAC_VOLKNOB, - STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT), { } /* end */ }; + static struct snd_kcontrol_new stac927x_mixer[] = { - STAC_INPUT_SOURCE, + STAC_INPUT_SOURCE(3), STAC_VOLKNOB, STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), - HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; -static struct snd_kcontrol_new stac9205_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - .count = 1, - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, - }, - STAC_INPUT_SOURCE, - STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), - STAC_VOLKNOB, - HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT), { } /* end */ }; @@ -1410,10 +1420,9 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { }; static struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .substreams = 2, .channels_min = 2, .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ + /* NID + .substreams is set in stac92xx_build_pcms */ .ops = { .prepare = stac92xx_capture_pcm_prepare, .cleanup = stac92xx_capture_pcm_cleanup @@ -1432,6 +1441,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; if (spec->alt_switch) { codec->num_pcms++; @@ -2478,6 +2488,7 @@ static int patch_stac9200(struct hda_codec *codec) spec->mux_nids = stac9200_mux_nids; spec->num_muxes = 1; spec->num_dmics = 0; + spec->num_adcs = 1; spec->init = stac9200_core_init; spec->mixer = stac9200_mixer; @@ -2529,6 +2540,7 @@ static int patch_stac925x(struct hda_codec *codec) spec->adc_nids = stac925x_adc_nids; spec->mux_nids = stac925x_mux_nids; spec->num_muxes = 1; + spec->num_adcs = 1; switch (codec->vendor_id) { case 0x83847632: /* STAC9202 */ case 0x83847633: /* STAC9202D */ @@ -2632,6 +2644,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); spec->num_dmics = 0; spec->init = stac922x_core_init; @@ -2700,22 +2713,25 @@ static int patch_stac927x(struct hda_codec *codec) spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; case STAC_D965_5ST: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; default: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = stac927x_core_init; spec->mixer = stac927x_mixer; @@ -2776,6 +2792,7 @@ static int patch_stac9205(struct hda_codec *codec) } spec->adc_nids = stac9205_adc_nids; + spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); spec->mux_nids = stac9205_mux_nids; spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); spec->dmic_nids = stac9205_dmic_nids; -- cgit v1.2.3 From 8da6470efbfd022c6d228f8829870ba018092b31 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Sep 2007 19:14:38 +0200 Subject: [ALSA] hda-codec - Add support for Acer Aspire 9303 Add the entry for Acer Aspire 9303 (model=acer-aspire) with ALC883 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3557865dde38..412629d02dbb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6971,6 +6971,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), -- cgit v1.2.3 From af6c016ecfd908203217a2d78715adeaa51b003d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Sep 2007 23:46:03 +0200 Subject: [ALSA] hda-codec - Fix wrong pin config order in STAC92xx dell models The last patch to change/add Dell models have wrong pin config orders. This patch fixes the pin positions. Taken from ALSA bug#3319, https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3319 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6dffa54e2da1..f843e2122a8b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -563,8 +563,8 @@ static unsigned int ref9200_pin_configs[8] = { 102801E8 */ static unsigned int dell9200_d21_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140, - 0x01813122, 0x02214030, 0x01014010, 0x02a19020, + 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, + 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; /* @@ -573,8 +573,8 @@ static unsigned int dell9200_d21_pin_configs[8] = { 102801C1 */ static unsigned int dell9200_d22_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x02a19021, 0x90100140, - 0x400001f2, 0x0221401f, 0x01014010, 0x01813020, + 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, + 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, }; /* @@ -587,8 +587,8 @@ static unsigned int dell9200_d22_pin_configs[8] = { 102801E3 */ static unsigned int dell9200_d23_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140, - 0x400001f2, 0x0221401f, 0x01014010, 0x01813020, + 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, + 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, }; @@ -598,8 +598,8 @@ static unsigned int dell9200_d23_pin_configs[8] = { 102801D8 (Dell Inspiron 640m) */ static unsigned int dell9200_m21_pin_configs[8] = { - 0x40c003fa, 0x03441340, 0x03a11020, 0x401003fc, - 0x403003fd, 0x0321121f, 0x0321121f, 0x408003fb, + 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, + 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, }; /* @@ -611,8 +611,8 @@ static unsigned int dell9200_m21_pin_configs[8] = { 102801D6 */ static unsigned int dell9200_m22_pin_configs[8] = { - 0x40c003fa, 0x0144131f, 0x03A11020, 0x401003fb, - 0x40f000fc, 0x0321121f, 0x90170310, 0x90a70321, + 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, + 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, }; /* @@ -633,8 +633,8 @@ static unsigned int dell9200_m23_pin_configs[8] = { 102801D3 */ static unsigned int dell9200_m24_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x03a11020, 0x401003fd, - 0x403003fe, 0x0321121f, 0x90170310, 0x408003fc, + 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, + 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, }; /* @@ -644,8 +644,8 @@ static unsigned int dell9200_m24_pin_configs[8] = { 102801EF */ static unsigned int dell9200_m25_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x04a11020, 0x401003fc, - 0x403003fd, 0x0421121f, 0x90170310, 0x408003fb, + 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, + 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, }; /* @@ -654,8 +654,8 @@ static unsigned int dell9200_m25_pin_configs[8] = { 102801F6 */ static unsigned int dell9200_m26_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x04a11020, 0x401003fd, - 0x403003fe, 0x0421121f, 0x90170310, 0x408003fc, + 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, + 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, }; /* @@ -663,8 +663,8 @@ static unsigned int dell9200_m26_pin_configs[8] = { 102801CD (Dell Inspiron E1705/9400) */ static unsigned int dell9200_m27_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x04a11020, 0x90170310, - 0x40f003fc, 0x0421121f, 0x90170310, 0x408003fb, + 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, + 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, }; -- cgit v1.2.3 From 8ab78c7424588c6b1600dcfd70418617a09326b8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Sep 2007 14:29:53 +0200 Subject: [ALSA] hda-codec - Add laptop-automute model for AD1986A Added a new model laptop-automute for AD1986A, which has the HP jack detection and auto-muting of the speaker. Currently, it's used for Lenovo N100. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_analog.c | 126 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index bc4b797aa97b..54cfd4526d20 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -74,6 +74,8 @@ struct ad198x_spec { struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + unsigned int jack_present :1; + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -588,6 +590,106 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { { } /* end */ }; +/* laptop-automute - 2ch only */ + +static void ad1986a_update_hp(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + unsigned int mute; + + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} + +static void ad1986a_hp_automute(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + ad1986a_update_hp(codec); +} + +#define AD1986A_HP_EVENT 0x37 + +static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) != AD1986A_HP_EVENT) + return; + ad1986a_hp_automute(codec); +} + +static int ad1986a_hp_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1986a_hp_automute(codec); + return 0; +} + +/* bind hp and internal speaker mute (with plug check) */ +static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + ad1986a_update_hp(codec); + return change; +} + +static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = ad1986a_hp_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + /* * initialization verbs */ @@ -701,12 +803,20 @@ static struct hda_verb ad1986a_ultra_init[] = { { } /* end */ }; +/* pin sensing on HP jack */ +static struct hda_verb ad1986a_hp_init_verbs[] = { + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, + {} +}; + + /* models */ enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, + AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, AD1986A_MODELS }; @@ -716,6 +826,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", + [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", }; @@ -744,7 +855,7 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), {} }; @@ -821,6 +932,19 @@ static int patch_ad1986a(struct hda_codec *codec) spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1986a_laptop_eapd_capture_source; break; + case AD1986A_LAPTOP_AUTOMUTE: + spec->mixers[0] = ad1986a_laptop_automute_mixers; + spec->num_init_verbs = 3; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->init_verbs[2] = ad1986a_hp_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; + codec->patch_ops.init = ad1986a_hp_init; + break; case AD1986A_ULTRA: spec->mixers[0] = ad1986a_laptop_eapd_mixers; spec->num_init_verbs = 2; -- cgit v1.2.3 From 914759b79e28ce74606e99d9f6aaabeec58394ab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Sep 2007 14:52:04 +0200 Subject: [ALSA] hda-codec - Add support for ASUS A7M Added the support for ASUS A7M with ALC882 codec. It's slightly different from ASUS A7J. The patch taken from ALSA bug#3000 https://bugtrack.alsa-project.org/alsa-bug/view.php?id=3000 Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 412629d02dbb..8491b046a9f4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -155,6 +155,7 @@ enum { ALC882_W2JC, ALC882_TARGA, ALC882_ASUS_A7J, + ALC882_ASUS_A7M, ALC885_MACPRO, ALC885_MBP3, ALC885_IMAC24, @@ -5022,6 +5023,22 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc882_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -5373,6 +5390,24 @@ static struct hda_verb alc882_asus_a7j_verbs[] = { { } /* end */ }; +static struct hda_verb alc882_asus_a7m_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + { } /* end */ +}; + static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) { unsigned int gpiostate, gpiomask, gpiodir; @@ -5563,6 +5598,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), @@ -5683,6 +5719,19 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, + alc880_gpio1_init_verbs, + alc882_asus_a7m_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, }; -- cgit v1.2.3 From 0438a00e64f38b2f655a10167f9f2d9759856069 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Sep 2007 14:54:11 +0200 Subject: [ALSA] hda-codec - Add missing model names for ALC882 codecs Added the missing model option strings for ALC882 codecs. Also added the corresponding description in ALSA-Configuration.txt. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8491b046a9f4..f06494a97761 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5585,6 +5585,9 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_6ST_DIG] = "6stack-dig", [ALC882_ARIMA] = "arima", [ALC882_W2JC] = "w2jc", + [ALC882_TARGA] = "targa", + [ALC882_ASUS_A7J] = "asus-a7j", + [ALC882_ASUS_A7M] = "asus-a7m", [ALC885_MACPRO] = "macpro", [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", -- cgit v1.2.3 From b875bf3aaf743fb461ab97e07752fbd825c2d78f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Sep 2007 15:00:27 +0200 Subject: [ALSA] hda-codec - Add quirk entry for Casper CPR2000 Added the quirk entry for Casper CPR2000 (model=acer) with ALC268 codec (ALSA bug#3343). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f06494a97761..90ab518dfe53 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9100,6 +9100,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), {} }; -- cgit v1.2.3 From 96fe7cc867b73690e806406be1562b0e6fa42d2d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Sep 2007 10:57:44 +0200 Subject: [ALSA] hda-codec - Add missing Mic Boost for some ALC882 models Mic Boost mixer volume was missing in some ALC882 models. Added now. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 90ab518dfe53..b36852ebb4b3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4999,8 +4999,10 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -5020,6 +5022,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), { } /* end */ }; -- cgit v1.2.3 From 8e7f00f9248c2dc6b36f3c4d1932aa975b454c48 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Sep 2007 10:58:58 +0200 Subject: [ALSA] hda-codec - Add support for Toshiba A305 Added the proper model=toshiba for Toshiba A305 with ALC268 codec. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b36852ebb4b3..e8270862e1e2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9100,6 +9100,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), -- cgit v1.2.3 From e45e459e88b81fe49129cc9a704fead0fc7d32ed Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Mon, 10 Sep 2007 23:09:42 +0200 Subject: [ALSA] hda: BIOS changing subsystem id Some laptop BIOS change the subsystem id for STAC9205 cards if the microphone isn't toggled on/off in the settings. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f843e2122a8b..2feb0f2e38c3 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1185,6 +1185,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { "Dell Precision", STAC_9205_M43xx), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, + "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, -- cgit v1.2.3 From e8a7f136f5edb6ae83b14faaa0da2a3c4558f431 Mon Sep 17 00:00:00 2001 From: Danny Tholen Date: Tue, 11 Sep 2007 21:41:56 +0200 Subject: [ALSA] hda-intel - Improve HD-audio codec probing robustness When modem is disabled in the BIOS, detection of the number of codecs always fails after booting if STATESTS is not cleared first. This patch fixes this problem and also adds an error check in a place where a read error would lead to a very large number of pointless loops. Signed-off-by: Danny Tholen Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 2 ++ sound/pci/hda/hda_intel.c | 3 +++ 2 files changed, 5 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e594de0b153e..535bcb7601b5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -155,6 +155,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, unsigned int parm; parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); + if (parm == -1) + return 0; *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 72fd34538994..68dc9a2e3cf8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -687,6 +687,9 @@ static int azx_reset(struct azx *chip) { int count; + /* clear STATESTS */ + azx_writeb(chip, STATESTS, STATESTS_INT_MASK); + /* reset controller */ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); -- cgit v1.2.3 From b201131c43c155c62e799d9410708d10b2c9a6ad Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 17 Sep 2007 12:45:11 +0200 Subject: [ALSA] hda-codec: Add 4 channel support for Realtek ALC883 I had a request for a 4 channel mode. This should implement front and surround outputs, leaving the 3rd plug for mic input. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e8270862e1e2..93ff155f5947 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6086,6 +6086,18 @@ static struct hda_verb alc883_3ST_ch2_init[] = { { } /* end */ }; +/* + * 4ch mode + */ +static struct hda_verb alc883_3ST_ch4_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + /* * 6ch mode */ @@ -6099,8 +6111,9 @@ static struct hda_verb alc883_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_modes[2] = { +static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { { 2, alc883_3ST_ch2_init }, + { 4, alc883_3ST_ch4_init }, { 6, alc883_3ST_ch6_init }, }; -- cgit v1.2.3 From 11370ee2c1c578a704f47d5513d57274c335db43 Mon Sep 17 00:00:00 2001 From: Tobin Davis Date: Mon, 17 Sep 2007 12:46:12 +0200 Subject: [ALSA] hda-codec: Add two new systems to ALC883 This patch adds support for the Asus M2A-VM HDMI and Abit IP35-PRO motherboards. Signed-off-by: Tobin Davis Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 93ff155f5947..b642c8bf162f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7054,6 +7054,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), {} }; -- cgit v1.2.3 From 33206e862edb930615a586f5156c2760ddb4bac0 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 17 Sep 2007 14:40:04 +0200 Subject: [ALSA] Intel HD Audio: Use list_for_each_entry(_safe) Intel HD Audio: Use list_for_each_entry(_safe) instead of list_for_each(_safe) Signed-off-by: Matthias Kaehlcke Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_generic.c | 25 +++++++------------------ sound/pci/hda/hda_intel.c | 7 ++----- 2 files changed, 9 insertions(+), 23 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 819c804a579f..c957eb58de5c 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -95,13 +95,12 @@ struct hda_gspec { static void snd_hda_generic_free(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p, *n; + struct hda_gnode *node, *n; if (! spec) return; /* free all widgets */ - list_for_each_safe(p, n, &spec->nid_list) { - struct hda_gnode *node = list_entry(p, struct hda_gnode, list); + list_for_each_entry_safe(node, n, &spec->nid_list, list) { if (node->conn_list != node->slist) kfree(node->conn_list); kfree(node); @@ -203,11 +202,9 @@ static int build_afg_tree(struct hda_codec *codec) /* FIXME: should avoid the braindead linear search */ static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) { - struct list_head *p; struct hda_gnode *node; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->nid == nid) return node; } @@ -260,11 +257,9 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no */ static void clear_check_flags(struct hda_gspec *spec) { - struct list_head *p; struct hda_gnode *node; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { node->checked = 0; } } @@ -347,12 +342,10 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, struct hda_gspec *spec, int jack_type) { - struct list_head *p; struct hda_gnode *node; int err; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->type != AC_WID_PIN) continue; /* output capable? */ @@ -664,7 +657,6 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) static int parse_input(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p; struct hda_gnode *node; int err; @@ -673,8 +665,7 @@ static int parse_input(struct hda_codec *codec) * If it reaches to certain input PINs, we take it as the * input path. */ - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->wid_caps & AC_WCAP_DIGITAL) continue; /* skip SPDIF */ if (node->type == AC_WID_AUD_IN) { @@ -943,7 +934,6 @@ static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, static int build_loopback_controls(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p; struct hda_gnode *node; int err; const char *type; @@ -951,8 +941,7 @@ static int build_loopback_controls(struct hda_codec *codec) if (! spec->out_pin_node[0]) return 0; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->type != AC_WID_PIN) continue; /* input capable? */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 68dc9a2e3cf8..cbb3da408e80 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1393,7 +1393,6 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, static int __devinit azx_pcm_create(struct azx *chip) { - struct list_head *p; struct hda_codec *codec; int c, err; int pcm_dev; @@ -1404,8 +1403,7 @@ static int __devinit azx_pcm_create(struct azx *chip) /* create audio PCMs */ pcm_dev = 0; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { if (codec->pcm_info[c].is_modem) continue; /* create later */ @@ -1424,8 +1422,7 @@ static int __devinit azx_pcm_create(struct azx *chip) /* create modem PCMs */ pcm_dev = AZX_MAX_AUDIO_PCMS; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { if (!codec->pcm_info[c].is_modem) continue; /* already created */ -- cgit v1.2.3 From 7a5a27cfaedf8589600b7ae585f3ca42b2d3c78a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Sep 2007 19:07:46 +0200 Subject: [ALSA] Add default values for power-saving as Kconfig options Added CONFIG_SND_AC97_POWER_SAVE_DEFAULT and CONFIG_SND_HDA_POWER_SAVE_DEFAULT Kconfig options as the default values for power-saving mode of AC97 and HD-audio drivers, respectively. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 535bcb7601b5..18ef0aa69d98 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -35,7 +35,7 @@ #ifdef CONFIG_SND_HDA_POWER_SAVE /* define this option here to hide as static */ -static int power_save = 10; +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; module_param(power_save, int, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); -- cgit v1.2.3 From b44ef2f1544a0a8d3d8907890662924082d0f1fa Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Tue, 18 Sep 2007 00:52:38 +0200 Subject: [ALSA] hda: More subsystem id BIOS changes More laptop BIOS changes the subsystem id for STAC9205 cards if the microphone is toggled on/off in the settings. The patch removes the old STAC_9205_M43xx and use STAC_9205_DELL_M43. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2feb0f2e38c3..27360d278bcf 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -57,7 +57,6 @@ enum { STAC_9205_DELL_M42, STAC_9205_DELL_M43, STAC_9205_DELL_M44, - STAC_9205_M43xx, STAC_9205_MODELS }; @@ -1163,7 +1162,6 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, - [STAC_9205_M43xx] = NULL, }; static const char *stac9205_models[STAC_9205_MODELS] = { @@ -1182,7 +1180,9 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, "unknown Dell", STAC_9205_DELL_M42), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, - "Dell Precision", STAC_9205_M43xx), + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, + "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, "Dell Precision", STAC_9205_DELL_M43), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, @@ -2807,7 +2807,6 @@ static int patch_stac9205(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; switch (spec->board_config){ - case STAC_9205_M43xx: case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ stac92xx_set_config_reg(codec, 0x1f, 0x01441030); -- cgit v1.2.3 From d86d01935a4c4c818514d8c23579703abd768329 Mon Sep 17 00:00:00 2001 From: Rene Herman Date: Tue, 18 Sep 2007 18:10:49 +0200 Subject: [ALSA] alsa-kernel: schedule_timeout() fixes Fix schedule_timeout() use in alsa-kernel. Mostly just schedule_timeout(1) --> schedule_timeout_uninterruptible(1) The wavefront_synth one fixes the surrounding loop as well. In ymfpci_main, delete a superfluous set_current_state() and in soc/soc-dapm.c replace an _interruptible with _uninterruptible in some debug code; it's not waiting for signals. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cbb3da408e80..4e3474c2b662 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -555,7 +555,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) } if (!chip->rirb.cmds) return chip->rirb.res; /* the last value */ - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(timeout, jiffies)); if (chip->msi) { -- cgit v1.2.3 From b60dd394f8af01d1b0a8b1d9d1aa6b75c645eb8e Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 20 Sep 2007 12:50:29 +0200 Subject: [ALSA] hda-codec - Fix ALC662 codec support * Fixed ALC662 init verbs (wrong NIDs) * Fixed ALC662 auto model issue (wrong DAC index) Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b642c8bf162f..096ef296db1a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11665,12 +11665,12 @@ static struct hda_verb alc662_init_verbs[] = { {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -11748,12 +11748,12 @@ static struct hda_verb alc662_auto_init_verbs[] = { /* set up input amps for analog loopback */ /* Amp Indices: DAC = 0, mixer = 1 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* FIXME: use matrix-type input source selection */ @@ -11935,7 +11935,7 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; - nid = alc880_idx_to_mixer(i); + nid = alc880_idx_to_dac(i); if (i == 2) { /* Center/LFE */ err = add_control(spec, ALC_CTL_WIDGET_VOL, -- cgit v1.2.3 From ac8842a0391a776dfa8f59cc83582f6feffa913b Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 20 Sep 2007 12:51:39 +0200 Subject: [ALSA] hda-codec - Missing support ASUS A7J Added the missing support for ASUS A7J [0x1043 0x1243] Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 096ef296db1a..ec14dd513fee 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5604,6 +5604,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), -- cgit v1.2.3 From c10710676728846f5c0a92431ebab2161f9c0b7e Mon Sep 17 00:00:00 2001 From: Peer Chen Date: Fri, 21 Sep 2007 18:20:25 +0200 Subject: [ALSA] alsa: Add the MCP79 support to hda_intel driver Add the MCP79 support to hda driver. The patch base on kernel 2.6.23-rc7 Signed-off-by: Peer Chen Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_intel.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4e3474c2b662..3fa0f9704909 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1959,6 +1959,10 @@ static struct pci_device_id azx_ids[] = { { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ + { 0x10de, 0x0ac0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); -- cgit v1.2.3 From 5513b0c58222d21b704cf352c554d9ab86c3fd97 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Oct 2007 11:58:41 +0200 Subject: [ALSA] hda-codec - Add zero checks in input-mux helper functions Added zero checks in input-mux helper functions to avoid Oops. Some devices may have no input pins while the driver registers control elements calling these functions. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 18ef0aa69d98..239cdd855dfe 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2341,6 +2341,8 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = imux->num_items; + if (!imux->num_items) + return 0; index = uinfo->value.enumerated.item; if (index >= imux->num_items) index = imux->num_items - 1; @@ -2356,6 +2358,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec, { unsigned int idx; + if (!imux->num_items) + return 0; idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; -- cgit v1.2.3 From 1194b5b70a0a000a4ace54d94d8df5cc3ec6e3e0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Oct 2007 10:04:26 +0200 Subject: [ALSA] hda-codec - Fix Gateway laptops with STAC9200 Fix the output of Gateway laptops with STAC9200 codec chip. They require the EAPD control for some pins. These pins shouldn't be powered down. To enable EAPD control, a new model 'gateway' was added to STAC9200. The known PCI SSIDs are included in the quirk list. The fix was originally suggested by Brian Hinz, in ALSA bug#2948. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/hda_codec.c | 16 +++++++++++++++- sound/pci/hda/patch_sigmatel.c | 21 +++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 239cdd855dfe..187533e477c6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1630,10 +1630,24 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { - if (get_wcaps(codec, nid) & AC_WCAP_POWER) + if (get_wcaps(codec, nid) & AC_WCAP_POWER) { + unsigned int pincap; + /* + * don't power down the widget if it controls eapd + * and EAPD_BTLENABLE is set. + */ + pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (pincap & AC_PINCAP_EAPD) { + int eapd = snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_EAPD_BTLENABLE, 0); + eapd &= 0x02; + if (power_state == AC_PWRST_D3 && eapd) + continue; + } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, power_state); + } } if (power_state == AC_PWRST_D0) { diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 27360d278bcf..fe91b9b46b61 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -49,6 +49,7 @@ enum { STAC_9200_DELL_M25, STAC_9200_DELL_M26, STAC_9200_DELL_M27, + STAC_9200_GATEWAY, STAC_9200_MODELS }; @@ -378,6 +379,13 @@ static struct hda_verb stac9200_core_init[] = { {} }; +static struct hda_verb stac9200_eapd_init[] = { + /* set dac0mux for dac converter */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {} +}; + static struct hda_verb stac925x_core_init[] = { /* set dac0mux for dac converter */ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -693,6 +701,7 @@ static const char *stac9200_models[STAC_9200_MODELS] = { [STAC_9200_DELL_M25] = "dell-m25", [STAC_9200_DELL_M26] = "dell-m26", [STAC_9200_DELL_M27] = "dell-m27", + [STAC_9200_GATEWAY] = "gateway", }; static struct snd_pci_quirk stac9200_cfg_tbl[] = { @@ -760,7 +769,12 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { "unknown Dell", STAC_9200_DELL_M26), /* Panasonic */ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), - + /* Gateway machines needs EAPD to be set on resume */ + SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY), + SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", + STAC_9200_GATEWAY), + SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", + STAC_9200_GATEWAY), {} /* terminator */ }; @@ -2492,7 +2506,10 @@ static int patch_stac9200(struct hda_codec *codec) spec->num_dmics = 0; spec->num_adcs = 1; - spec->init = stac9200_core_init; + if (spec->board_config == STAC_9200_GATEWAY) + spec->init = stac9200_eapd_init; + else + spec->init = stac9200_core_init; spec->mixer = stac9200_mixer; err = stac9200_parse_auto_config(codec); -- cgit v1.2.3 From 5e915bb3677f1369223a87e488c340236f81bfc2 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Wed, 10 Oct 2007 10:42:00 +0200 Subject: [ALSA] hda-codec - Re-add quirk support for Dell XPS 1330 and Inspiron 1420 Signed-off-by: Tim Gardner Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fe91b9b46b61..9fae4f1296bb 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1111,11 +1111,13 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST), /* Dell 3 stack systems */ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), /* 965 based 5 stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), -- cgit v1.2.3 From a3a2f429e55997e3b7a0c23baf1208991970ecc1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Oct 2007 11:21:21 +0200 Subject: [ALSA] hda-codec - Fix input_mux numbers for vaio stac92xx My bad, I forgot to update the num_items field when added a new item to vaio_mux items table, so the last item 'PCM' disappeared. Now it has the right number 3. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9fae4f1296bb..8b3576007d4a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2875,7 +2875,7 @@ static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; static hda_nid_t vaio_mux_nids[] = { 0x15 }; static struct hda_input_mux vaio_mux = { - .num_items = 2, + .num_items = 3, .items = { /* { "HP", 0x0 }, */ { "Mic Jack", 0x1 }, -- cgit v1.2.3 From 39d3ed381877246719184897c853c0c58028fe54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 Oct 2007 15:03:48 +0200 Subject: [ALSA] hda-codec - Fix for Fujitsu Lifebook C1410 Fixed ALC262 fujitsu model to support Fujitsu Lifebook C1410 properly. It requires EAPD and has separate int/ext mic inputs (which was missing in the current driver). Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ec14dd513fee..1d2cd4c4b160 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7807,9 +7807,10 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = { }; static struct hda_input_mux alc262_fujitsu_capture_source = { - .num_items = 2, + .num_items = 3, .items = { { "Mic", 0x0 }, + { "Int Mic", 0x1 }, { "CD", 0x4 }, }, }; @@ -7915,6 +7916,9 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -8411,7 +8415,8 @@ static struct alc_config_preset alc262_presets[] = { }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, - .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, + alc262_fujitsu_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, .hp_nid = 0x03, -- cgit v1.2.3 From 9066f2443122c1501da64b6faa0038c13f0209f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Oct 2007 14:25:16 +0200 Subject: [ALSA] hda-codec - Fix STAC922x volume knob control Reported by zhejiang 'I found that STAC_VOLKNOB hardwired the KNOB nid to 0x24. It is okay for stac9205 and stac927x. But the VolumeKnob nid of stac9220-9221 is 0x16.' Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8b3576007d4a..626a5edde06c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -352,7 +352,7 @@ static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = kcontrol->private_value; + ucontrol->value.integer.value[0] = kcontrol->private_value & 0xff; return 0; } @@ -360,15 +360,17 @@ static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int val = kcontrol->private_value & 0xff; - if (kcontrol->private_value == ucontrol->value.integer.value[0]) + if (val == ucontrol->value.integer.value[0]) return 0; - kcontrol->private_value = ucontrol->value.integer.value[0]; + val = ucontrol->value.integer.value[0]; + kcontrol->private_value &= ~0xff; + kcontrol->private_value |= val; - snd_hda_codec_write_cache(codec, 0x24, 0, - AC_VERB_SET_VOLUME_KNOB_CONTROL, - kcontrol->private_value | 0x80); + snd_hda_codec_write_cache(codec, kcontrol->private_value >> 16, 0, + AC_VERB_SET_VOLUME_KNOB_CONTROL, val | 0x80); return 1; } @@ -441,7 +443,7 @@ static struct hda_verb stac9205_core_init[] = { .private_value = verb_read | (verb_write << 16), \ } -#define STAC_VOLKNOB \ +#define STAC_VOLKNOB(knob_nid) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = "Master Playback Volume", \ @@ -449,7 +451,7 @@ static struct hda_verb stac9205_core_init[] = { .info = stac92xx_volknob_info, \ .get = stac92xx_volknob_get, \ .put = stac92xx_volknob_put, \ - .private_value = 127, \ + .private_value = 127 | (knob_nid << 16), \ } @@ -482,7 +484,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { }, STAC_INPUT_SOURCE(2), STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), - STAC_VOLKNOB, + STAC_VOLKNOB(0x24), HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), @@ -498,7 +500,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac922x_mixer[] = { STAC_INPUT_SOURCE(2), - STAC_VOLKNOB, + STAC_VOLKNOB(0x16), HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), @@ -512,7 +514,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { static struct snd_kcontrol_new stac927x_mixer[] = { STAC_INPUT_SOURCE(3), - STAC_VOLKNOB, + STAC_VOLKNOB(0x24), STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), -- cgit v1.2.3 From f6e9852ad05fa28301c83d4e2b082620de010358 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Oct 2007 14:27:04 +0200 Subject: [ALSA] hda-codec - Add array terminator for dmic in STAC codec Reported by Jan-Marek Glogowski. The dmic array is passed to snd_hda_parse_pin_def_config() and should be zero-terminated. Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_sigmatel.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 626a5edde06c..bf950195107c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -183,8 +183,9 @@ static hda_nid_t stac925x_dac_nids[1] = { 0x02, }; -static hda_nid_t stac925x_dmic_nids[1] = { - 0x15, +#define STAC925X_NUM_DMICS 1 +static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { + 0x15, 0 }; static hda_nid_t stac922x_adc_nids[2] = { @@ -211,8 +212,9 @@ static hda_nid_t stac9205_mux_nids[2] = { 0x19, 0x1a }; -static hda_nid_t stac9205_dmic_nids[2] = { - 0x17, 0x18, +#define STAC9205_NUM_DMICS 2 +static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { + 0x17, 0x18, 0 }; static hda_nid_t stac9200_pin_nids[8] = { @@ -2569,7 +2571,7 @@ static int patch_stac925x(struct hda_codec *codec) case 0x83847633: /* STAC9202D */ case 0x83847636: /* STAC9251 */ case 0x83847637: /* STAC9251D */ - spec->num_dmics = 1; + spec->num_dmics = STAC925X_NUM_DMICS; spec->dmic_nids = stac925x_dmic_nids; break; default: @@ -2819,7 +2821,7 @@ static int patch_stac9205(struct hda_codec *codec) spec->mux_nids = stac9205_mux_nids; spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); spec->dmic_nids = stac9205_dmic_nids; - spec->num_dmics = ARRAY_SIZE(stac9205_dmic_nids); + spec->num_dmics = STAC9205_NUM_DMICS; spec->dmux_nid = 0x1d; spec->init = stac9205_core_init; -- cgit v1.2.3 From 291702f017efdfe556cb87b8530eb7d1ff08cbae Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 16 Oct 2007 14:28:03 +0200 Subject: [ALSA] Support ASUS P701 eeepc [0x1043 0x82a1] support Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 100 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 6 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1d2cd4c4b160..c8ca97b2c31d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -143,6 +143,7 @@ enum { ALC662_3ST_6ch, ALC662_5ST_DIG, ALC662_LENOVO_101E, + ALC662_ASUS_EEEPC_P701, ALC662_AUTO, ALC662_MODEL_LAST, }; @@ -11432,6 +11433,15 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { { "Line", 0x2 }, }, }; + +static struct hda_input_mux alc662_eeepc_capture_source = { + .num_items = 2, + .items = { + { "i-Mic", 0x1 }, + { "e-Mic", 0x0 }, + }, +}; + #define alc662_mux_enum_info alc_mux_enum_info #define alc662_mux_enum_get alc_mux_enum_get @@ -11648,6 +11658,22 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { + HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -11713,13 +11739,24 @@ static struct hda_verb alc662_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, { } }; static struct hda_verb alc662_sue_init_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, - {} + {} +}; + +static struct hda_verb alc662_eeepc_sue_init_verbs[] = { + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} }; /* @@ -11825,6 +11862,39 @@ static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, alc662_lenovo_101e_ispeaker_automute(codec); } +static void alc662_eeepc_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); +} + +/* unsolicited event for HP jack sensing */ +static void alc662_eeepc_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc262_hippo1_automute( codec ); + + if ((res >> 26) == ALC880_MIC_EVENT) + alc662_eeepc_mic_automute(codec); +} + +static void alc662_eeepc_inithook(struct hda_codec *codec) +{ + alc262_hippo1_automute( codec ); + alc662_eeepc_mic_automute(codec); +} + #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc662_loopbacks alc880_loopbacks #endif @@ -11850,12 +11920,13 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), {} }; static struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, + .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11868,7 +11939,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11882,7 +11954,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11894,7 +11967,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, + .mixers = { alc662_base_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11907,7 +11981,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, + .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11919,6 +11993,20 @@ static struct alc_config_preset alc662_presets[] = { .unsol_event = alc662_lenovo_101e_unsol_event, .init_hook = alc662_lenovo_101e_all_automute, }, + [ALC662_ASUS_EEEPC_P701] = { + .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eeepc_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), + .adc_nids = alc662_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, + .unsol_event = alc662_eeepc_unsol_event, + .init_hook = alc662_eeepc_inithook, + }, }; -- cgit v1.2.3 From c9b58006be7e471a5f55d171cbaa08f4aa8078ea Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 16 Oct 2007 14:30:01 +0200 Subject: [ALSA] hda-codec - Fix SKU ID function for realtek codecs Fixed SKU ID function for realtek codecs. It's used by the automatic BIOS configuration mode. Now it supports the correct jack-detection mechanism, too. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 193 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 168 insertions(+), 25 deletions(-) (limited to 'sound/pci/hda') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c8ca97b2c31d..53b0428abfc2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -662,6 +662,44 @@ static struct hda_verb alc_gpio3_init_verbs[] = { { } }; +static void alc_sku_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; + unsigned int hp_nid = spec->autocfg.hp_pins[0]; + unsigned int sp_nid = spec->autocfg.speaker_pins[0]; + + /* need to execute and sync at first */ + snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, hp_nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if (codec->vendor_id == 0x10ec0880) + res >>= 28; + else + res >>= 26; + if (res != ALC880_HP_EVENT) + return; + + alc_sku_automute(codec); +} + /* 32-bit subsystem ID for BIOS loading in HD Audio codec. * 31 ~ 16 : Manufacture ID * 15 ~ 8 : SKU ID @@ -672,13 +710,48 @@ static void alc_subsystem_id(struct hda_codec *codec, unsigned int porta, unsigned int porte, unsigned int portd) { - unsigned int ass, tmp; + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; - ass = codec->subsystem_id; - if (!(ass & 1)) + ass = codec->subsystem_id & 0xffff; + if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + goto do_sku; + + /* + * 31~30 : port conetcivity + * 29~21 : reserve + * 20 : PCBEEP input + * 19~16 : Check sum (15:1) + * 15~1 : Custom + * 0 : override + */ + nid = 0x1d; + if (codec->vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (!(ass & 1) && !(ass & 0x100000)) + return; + if ((ass >> 30) != 1) /* no physical connection */ return; - /* Override */ + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) && 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return; +do_sku: + /* + * 0 : override + * 1 : Swap Jack + * 2 : 0 --> Desktop, 1 --> Laptop + * 3~5 : External Amplifier control + * 7~6 : Reserved + */ tmp = (ass & 0x38) >> 3; /* external Amp control */ switch (tmp) { case 1: @@ -690,38 +763,108 @@ static void alc_subsystem_id(struct hda_codec *codec, case 7: snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; - case 5: + case 5: /* set EAPD output high */ switch (codec->vendor_id) { - case 0x10ec0862: - case 0x10ec0660: - case 0x10ec0662: + case 0x10ec0260: + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_EAPD_BTLENABLE, 2); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_EAPD_BTLENABLE, 2); + break; + case 0x10ec0262: case 0x10ec0267: case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0862: + case 0x10ec0662: snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_EAPD_BTLENABLE, 2); snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_EAPD_BTLENABLE, 2); - return; + break; } - case 6: - if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ - hda_nid_t port = 0; - tmp = (ass & 0x1800) >> 11; - switch (tmp) { - case 0: port = porta; break; - case 1: port = porte; break; - case 2: port = portd; break; - } - if (port) - snd_hda_codec_write(codec, port, 0, - AC_VERB_SET_EAPD_BTLENABLE, - 2); + switch (codec->vendor_id) { + case 0x10ec0260: + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x2010); + break; + case 0x10ec0262: + case 0x10ec0880: + case 0x10ec0882: + case 0x10ec0883: + case 0x10ec0885: + case 0x10ec0888: + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x2010); + break; + case 0x10ec0267: + case 0x10ec0268: + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x3000); + break; } - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, - (tmp == 5 ? 0x3040 : 0x3050)); + default: break; } + + /* is laptop and enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ + if (!(ass & 0x4) || !(ass & 0x8000)) + return; + /* + * 10~8 : Jack location + * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered + * 14~13: Resvered + * 15 : 1 --> enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ + if (!spec->autocfg.speaker_pins[0]) { + if (spec->multiout.dac_nids[0]) + spec->autocfg.speaker_pins[0] = + spec->multiout.dac_nids[0]; + else + return; + } + + if (!spec->autocfg.hp_pins[0]) { + tmp = (ass >> 11) & 0x3; /* HP to chassis */ + if (tmp == 0) + spec->autocfg.hp_pins[0] = porta; + else if (tmp == 1) + spec->autocfg.hp_pins[0] = porte; + else if (tmp == 2) + spec->autocfg.hp_pins[0] = portd; + else + return; + } + + snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_HP_EVENT); + spec->unsol_event = alc_sku_unsol_event; + spec->init_hook = alc_sku_automute; } /* -- cgit v1.2.3