summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/dell_wmi_helper.c116
-rw-r--r--sound/pci/hda/hda_codec.c93
-rw-r--r--sound/pci/hda/hda_codec.h6
-rw-r--r--sound/pci/hda/hda_generic.c144
-rw-r--r--sound/pci/hda/hda_generic.h16
-rw-r--r--sound/pci/hda/hda_intel.c5
-rw-r--r--sound/pci/hda/patch_analog.c4
-rw-r--r--sound/pci/hda/patch_cirrus.c29
-rw-r--r--sound/pci/hda/patch_conexant.c100
-rw-r--r--sound/pci/hda/patch_hdmi.c4
-rw-r--r--sound/pci/hda/patch_realtek.c852
-rw-r--r--sound/pci/hda/patch_sigmatel.c31
-rw-r--r--sound/pci/hda/patch_via.c294
-rw-r--r--sound/pci/hda/thinkpad_helper.c27
14 files changed, 879 insertions, 842 deletions
diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c
index 1b48a8c19d28..8a7dbd1a7fbf 100644
--- a/sound/pci/hda/dell_wmi_helper.c
+++ b/sound/pci/hda/dell_wmi_helper.c
@@ -6,111 +6,18 @@
#if IS_ENABLED(CONFIG_DELL_LAPTOP)
#include <linux/dell-led.h>
-enum {
- MICMUTE_LED_ON,
- MICMUTE_LED_OFF,
- MICMUTE_LED_FOLLOW_CAPTURE,
- MICMUTE_LED_FOLLOW_MUTE,
-};
-
-static int dell_led_mode = MICMUTE_LED_FOLLOW_MUTE;
-static int dell_capture;
-static int dell_led_value;
static int (*dell_micmute_led_set_func)(int);
-static void (*dell_old_cap_hook)(struct hda_codec *,
- struct snd_kcontrol *,
- struct snd_ctl_elem_value *);
-
-static void call_micmute_led_update(void)
-{
- int val;
-
- switch (dell_led_mode) {
- case MICMUTE_LED_ON:
- val = 1;
- break;
- case MICMUTE_LED_OFF:
- val = 0;
- break;
- case MICMUTE_LED_FOLLOW_CAPTURE:
- val = dell_capture;
- break;
- case MICMUTE_LED_FOLLOW_MUTE:
- default:
- val = !dell_capture;
- break;
- }
-
- if (val == dell_led_value)
- return;
- dell_led_value = val;
- dell_micmute_led_set_func(dell_led_value);
-}
-
-static void update_dell_wmi_micmute_led(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- if (dell_old_cap_hook)
- dell_old_cap_hook(codec, kcontrol, ucontrol);
-
- if (!ucontrol || !dell_micmute_led_set_func)
- return;
- if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
- /* TODO: How do I verify if it's a mono or stereo here? */
- dell_capture = (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
- call_micmute_led_update();
- }
-}
-static int dell_mic_mute_led_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static void dell_micmute_update(struct hda_codec *codec)
{
- static const char * const texts[] = {
- "On", "Off", "Follow Capture", "Follow Mute",
- };
-
- return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
-}
+ struct hda_gen_spec *spec = codec->spec;
-static int dell_mic_mute_led_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] = dell_led_mode;
- return 0;
+ dell_micmute_led_set_func(spec->micmute_led.led_value);
}
-static int dell_mic_mute_led_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- unsigned int mode;
-
- mode = ucontrol->value.enumerated.item[0];
- if (mode > MICMUTE_LED_FOLLOW_MUTE)
- mode = MICMUTE_LED_FOLLOW_MUTE;
- if (mode == dell_led_mode)
- return 0;
- dell_led_mode = mode;
- call_micmute_led_update();
- return 1;
-}
-
-static const struct snd_kcontrol_new dell_mic_mute_mode_ctls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic Mute-LED Mode",
- .info = dell_mic_mute_led_mode_info,
- .get = dell_mic_mute_led_mode_get,
- .put = dell_mic_mute_led_mode_put,
- },
- {}
-};
-
static void alc_fixup_dell_wmi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
bool removefunc = false;
if (action == HDA_FIXUP_ACT_PROBE) {
@@ -121,25 +28,14 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec,
return;
}
- removefunc = true;
- if (dell_micmute_led_set_func(false) >= 0) {
- dell_led_value = 0;
- if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch)
- codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
- else {
- dell_old_cap_hook = spec->gen.cap_sync_hook;
- spec->gen.cap_sync_hook = update_dell_wmi_micmute_led;
- removefunc = false;
- add_mixer(spec, dell_mic_mute_mode_ctls);
- }
- }
-
+ removefunc = (dell_micmute_led_set_func(false) < 0) ||
+ (snd_hda_gen_add_micmute_led(codec,
+ dell_micmute_update) <= 0);
}
if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
symbol_put(dell_micmute_led_set);
dell_micmute_led_set_func = NULL;
- dell_old_cap_hook = NULL;
}
}
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 20a171ac4bb2..6d0c0b143270 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -37,15 +37,8 @@
#include "hda_jack.h"
#include <sound/hda_hwdep.h>
-#ifdef CONFIG_PM
-#define codec_in_pm(codec) atomic_read(&(codec)->core.in_pm)
-#define hda_codec_is_power_on(codec) \
- (!pm_runtime_suspended(hda_codec_dev(codec)))
-#else
-#define codec_in_pm(codec) 0
-#define hda_codec_is_power_on(codec) 1
-#endif
-
+#define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core)
+#define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core)
#define codec_has_epss(codec) \
((codec)->core.power_caps & AC_PWRST_EPSS)
#define codec_has_clkstop(codec) \
@@ -858,6 +851,39 @@ static void snd_hda_codec_dev_release(struct device *dev)
kfree(codec);
}
+#define DEV_NAME_LEN 31
+
+static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card,
+ unsigned int codec_addr, struct hda_codec **codecp)
+{
+ char name[DEV_NAME_LEN];
+ struct hda_codec *codec;
+ int err;
+
+ dev_dbg(card->dev, "%s: entry\n", __func__);
+
+ if (snd_BUG_ON(!bus))
+ return -EINVAL;
+ if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
+ return -EINVAL;
+
+ codec = kzalloc(sizeof(*codec), GFP_KERNEL);
+ if (!codec)
+ return -ENOMEM;
+
+ sprintf(name, "hdaudioC%dD%d", card->number, codec_addr);
+ err = snd_hdac_device_init(&codec->core, &bus->core, name, codec_addr);
+ if (err < 0) {
+ kfree(codec);
+ return err;
+ }
+
+ codec->core.type = HDA_DEV_LEGACY;
+ *codecp = codec;
+
+ return err;
+}
+
/**
* snd_hda_codec_new - create a HDA codec
* @bus: the bus to assign
@@ -869,7 +895,19 @@ static void snd_hda_codec_dev_release(struct device *dev)
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
unsigned int codec_addr, struct hda_codec **codecp)
{
- struct hda_codec *codec;
+ int ret;
+
+ ret = snd_hda_codec_device_init(bus, card, codec_addr, codecp);
+ if (ret < 0)
+ return ret;
+
+ return snd_hda_codec_device_new(bus, card, codec_addr, *codecp);
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+
+int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
+ unsigned int codec_addr, struct hda_codec *codec)
+{
char component[31];
hda_nid_t fg;
int err;
@@ -879,25 +917,14 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
.dev_free = snd_hda_codec_dev_free,
};
+ dev_dbg(card->dev, "%s: entry\n", __func__);
+
if (snd_BUG_ON(!bus))
return -EINVAL;
if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
return -EINVAL;
- codec = kzalloc(sizeof(*codec), GFP_KERNEL);
- if (!codec)
- return -ENOMEM;
-
- sprintf(component, "hdaudioC%dD%d", card->number, codec_addr);
- err = snd_hdac_device_init(&codec->core, &bus->core, component,
- codec_addr);
- if (err < 0) {
- kfree(codec);
- return err;
- }
-
codec->core.dev.release = snd_hda_codec_dev_release;
- codec->core.type = HDA_DEV_LEGACY;
codec->core.exec_verb = codec_exec_verb;
codec->bus = bus;
@@ -957,15 +984,13 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
if (err < 0)
goto error;
- if (codecp)
- *codecp = codec;
return 0;
error:
put_device(hda_codec_dev(codec));
return err;
}
-EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+EXPORT_SYMBOL_GPL(snd_hda_codec_device_new);
/**
* snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
@@ -2846,14 +2871,13 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
{
unsigned int state;
- atomic_inc(&codec->core.in_pm);
-
+ snd_hdac_enter_pm(&codec->core);
if (codec->patch_ops.suspend)
codec->patch_ops.suspend(codec);
hda_cleanup_all_streams(codec);
state = hda_set_power_state(codec, AC_PWRST_D3);
update_power_acct(codec, true);
- atomic_dec(&codec->core.in_pm);
+ snd_hdac_leave_pm(&codec->core);
return state;
}
@@ -2862,8 +2886,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
*/
static void hda_call_codec_resume(struct hda_codec *codec)
{
- atomic_inc(&codec->core.in_pm);
-
+ snd_hdac_enter_pm(&codec->core);
if (codec->core.regmap)
regcache_mark_dirty(codec->core.regmap);
@@ -2886,7 +2909,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
hda_jackpoll_work(&codec->jackpoll_work.work);
else
snd_hda_jack_report_sync(codec);
- atomic_dec(&codec->core.in_pm);
+ snd_hdac_leave_pm(&codec->core);
}
static int hda_codec_runtime_suspend(struct device *dev)
@@ -2992,6 +3015,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
sync_power_up_states(codec);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_build_controls);
/*
* PCM stuff
@@ -3197,6 +3221,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_parse_pcms);
/* assign all PCMs of the given codec */
int snd_hda_codec_build_pcms(struct hda_codec *codec)
@@ -3843,7 +3868,7 @@ EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl);
* This function is a helper to set a pin ctl value more safely.
* It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the
* value in pin target array via snd_hda_codec_set_pin_target(), then
- * actually writes the value via either snd_hda_codec_update_cache() or
+ * actually writes the value via either snd_hda_codec_write_cache() or
* snd_hda_codec_write() depending on @cached flag.
*/
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
@@ -3852,7 +3877,7 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
val = snd_hda_correct_pin_ctl(codec, pin, val);
snd_hda_codec_set_pin_target(codec, pin, val);
if (cached)
- return snd_hda_codec_update_cache(codec, pin, 0,
+ return snd_hda_codec_write_cache(codec, pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
else
return snd_hda_codec_write(codec, pin, 0,
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index a8b1b31f161c..0d98bb9068b1 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -84,6 +84,7 @@ struct hda_bus {
*/
typedef int (*hda_codec_patch_t)(struct hda_codec *);
+#define HDA_CODEC_ID_SKIP_PROBE 0x00000001
#define HDA_CODEC_ID_GENERIC_HDMI 0x00000101
#define HDA_CODEC_ID_GENERIC 0x00000201
@@ -308,6 +309,8 @@ struct hda_codec {
*/
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
unsigned int codec_addr, struct hda_codec **codecp);
+int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
+ unsigned int codec_addr, struct hda_codec *codec);
int snd_hda_codec_configure(struct hda_codec *codec);
int snd_hda_codec_update_widgets(struct hda_codec *codec);
@@ -382,9 +385,6 @@ snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
return snd_hdac_regmap_write(&codec->core, nid, verb, parm);
}
-#define snd_hda_codec_update_cache(codec, nid, flags, verb, parm) \
- snd_hda_codec_write_cache(codec, nid, flags, verb, parm)
-
/* the struct for codec->pin_configs */
struct hda_pincfg {
hda_nid_t nid;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index db773e219aaa..579984ecdec3 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -209,7 +209,7 @@ static void parse_user_hints(struct hda_codec *codec)
*/
#define update_pin_ctl(codec, pin, val) \
- snd_hda_codec_update_cache(codec, pin, 0, \
+ snd_hda_codec_write_cache(codec, pin, 0, \
AC_VERB_SET_PIN_WIDGET_CONTROL, val)
/* restore the pinctl based on the cached value */
@@ -898,7 +898,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
hda_nid_t nid = path->path[i];
if (enable && path->multi[i])
- snd_hda_codec_update_cache(codec, nid, 0,
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
path->idx[i]);
if (has_amp_in(codec, path, i))
@@ -930,7 +930,7 @@ static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
return;
if (codec->inv_eapd)
enable = !enable;
- snd_hda_codec_update_cache(codec, pin, 0,
+ snd_hda_codec_write_cache(codec, pin, 0,
AC_VERB_SET_EAPD_BTLENABLE,
enable ? 0x02 : 0x00);
}
@@ -3900,6 +3900,142 @@ static int parse_mic_boost(struct hda_codec *codec)
}
/*
+ * mic mute LED hook helpers
+ */
+enum {
+ MICMUTE_LED_ON,
+ MICMUTE_LED_OFF,
+ MICMUTE_LED_FOLLOW_CAPTURE,
+ MICMUTE_LED_FOLLOW_MUTE,
+};
+
+static void call_micmute_led_update(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int val;
+
+ switch (spec->micmute_led.led_mode) {
+ case MICMUTE_LED_ON:
+ val = 1;
+ break;
+ case MICMUTE_LED_OFF:
+ val = 0;
+ break;
+ case MICMUTE_LED_FOLLOW_CAPTURE:
+ val = !!spec->micmute_led.capture;
+ break;
+ case MICMUTE_LED_FOLLOW_MUTE:
+ default:
+ val = !spec->micmute_led.capture;
+ break;
+ }
+
+ if (val == spec->micmute_led.led_value)
+ return;
+ spec->micmute_led.led_value = val;
+ if (spec->micmute_led.update)
+ spec->micmute_led.update(codec);
+}
+
+static void update_micmute_led(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int mask;
+
+ if (spec->micmute_led.old_hook)
+ spec->micmute_led.old_hook(codec, kcontrol, ucontrol);
+
+ if (!ucontrol)
+ return;
+ mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (!strcmp("Capture Switch", ucontrol->id.name)) {
+ /* TODO: How do I verify if it's a mono or stereo here? */
+ if (ucontrol->value.integer.value[0] ||
+ ucontrol->value.integer.value[1])
+ spec->micmute_led.capture |= mask;
+ else
+ spec->micmute_led.capture &= ~mask;
+ call_micmute_led_update(codec);
+ }
+}
+
+static int micmute_led_mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char * const texts[] = {
+ "On", "Off", "Follow Capture", "Follow Mute",
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int micmute_led_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode;
+ return 0;
+}
+
+static int micmute_led_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int mode;
+
+ mode = ucontrol->value.enumerated.item[0];
+ if (mode > MICMUTE_LED_FOLLOW_MUTE)
+ mode = MICMUTE_LED_FOLLOW_MUTE;
+ if (mode == spec->micmute_led.led_mode)
+ return 0;
+ spec->micmute_led.led_mode = mode;
+ call_micmute_led_update(codec);
+ return 1;
+}
+
+static const struct snd_kcontrol_new micmute_led_mode_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic Mute-LED Mode",
+ .info = micmute_led_mode_info,
+ .get = micmute_led_mode_get,
+ .put = micmute_led_mode_put,
+};
+
+/**
+ * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook
+ * @codec: the HDA codec
+ * @hook: the callback for updating LED
+ *
+ * Called from the codec drivers for offering the mic mute LED controls.
+ * When established, it sets up cap_sync_hook and triggers the callback at
+ * each time when the capture mixer switch changes. The callback is supposed
+ * to update the LED accordingly.
+ *
+ * Returns 0 if the hook is established or a negative error code.
+ */
+int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
+ void (*hook)(struct hda_codec *))
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
+ spec->micmute_led.capture = 0;
+ spec->micmute_led.led_value = 0;
+ spec->micmute_led.old_hook = spec->cap_sync_hook;
+ spec->micmute_led.update = hook;
+ spec->cap_sync_hook = update_micmute_led;
+ if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
+ return -ENOMEM;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
+
+/*
* parse digital I/Os and set up NIDs in BIOS auto-parse mode
*/
static void parse_digital(struct hda_codec *codec)
@@ -5837,7 +5973,7 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec)
hda_nid_t nid = pin->nid;
if (is_jack_detectable(codec, nid) &&
!snd_hda_jack_tbl_get(codec, nid))
- snd_hda_codec_update_cache(codec, nid, 0,
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE, 0);
}
}
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 61772317de46..10123664fa61 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -86,6 +86,16 @@ struct badness_table {
extern const struct badness_table hda_main_out_badness;
extern const struct badness_table hda_extra_out_badness;
+struct hda_micmute_hook {
+ unsigned int led_mode;
+ unsigned int capture;
+ unsigned int led_value;
+ void (*update)(struct hda_codec *codec);
+ void (*old_hook)(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+};
+
struct hda_gen_spec {
char stream_name_analog[32]; /* analog PCM stream */
const struct hda_pcm_stream *stream_analog_playback;
@@ -276,6 +286,9 @@ struct hda_gen_spec {
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+ /* mic mute LED hook; called via cap_sync_hook */
+ struct hda_micmute_hook micmute_led;
+
/* PCM hooks */
void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
@@ -342,4 +355,7 @@ unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
+int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
+ void (*hook)(struct hda_codec *));
+
#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1ae1850b3bfd..daedf662b940 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1429,7 +1429,7 @@ static struct pci_dev *get_bound_vga(struct pci_dev *pci)
p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
pci->bus->number, 0);
if (p) {
- if ((p->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+ if ((p->class >> 16) == PCI_BASE_CLASS_DISPLAY)
return p;
pci_dev_put(p);
}
@@ -2535,7 +2535,8 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
/* AMD Raven */
{ PCI_DEVICE(0x1022, 0x15e3),
- .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
+ .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
+ AZX_DCAPS_PM_RUNTIME },
/* ATI HDMI */
{ PCI_DEVICE(0x1002, 0x0002),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 757857313426..fd476fb40e1b 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -148,7 +148,7 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled)
return;
if (codec->inv_eapd)
enabled = !enabled;
- snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
+ snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
AC_VERB_SET_EAPD_BTLENABLE,
enabled ? 0x02 : 0x00);
}
@@ -991,7 +991,7 @@ static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
if (spec->eapd_nid)
ad_vmaster_eapd_hook(private_data, enabled);
- snd_hda_codec_update_cache(codec, 0x01, 0,
+ snd_hda_codec_write_cache(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA,
enabled ? 0x00 : 0x02);
}
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index d6e079f4ec09..a7f91be45194 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1096,25 +1096,6 @@ static int cs421x_init(struct hda_codec *codec)
return 0;
}
-static int cs421x_build_controls(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- if (spec->gen.autocfg.speaker_outs &&
- spec->vendor_nid == CS4210_VENDOR_NID) {
- err = snd_hda_ctl_add(codec, 0,
- snd_ctl_new1(&cs421x_speaker_boost_ctl, codec));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
{
unsigned int caps;
@@ -1144,6 +1125,14 @@ static int cs421x_parse_auto_config(struct hda_codec *codec)
return err;
parse_cs421x_digital(codec);
+
+ if (spec->gen.autocfg.speaker_outs &&
+ spec->vendor_nid == CS4210_VENDOR_NID) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &cs421x_speaker_boost_ctl))
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1175,7 +1164,7 @@ static int cs421x_suspend(struct hda_codec *codec)
#endif
static const struct hda_codec_ops cs421x_patch_ops = {
- .build_controls = cs421x_build_controls,
+ .build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = cs421x_init,
.free = cs_free,
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index f641c20095f7..08e32be4cc5c 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -37,8 +37,6 @@
struct conexant_spec {
struct hda_gen_spec gen;
- unsigned int beep_amp;
-
/* extra EAPD pins */
unsigned int num_eapds;
hda_nid_t eapds[4];
@@ -62,65 +60,48 @@ struct conexant_spec {
#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
- int idx, int dir)
-{
- spec->gen.beep_nid = nid;
- spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-}
-/* additional beep mixers; the actual parameters are overwritten at build */
+/* additional beep mixers; private_value will be overwritten */
static const struct snd_kcontrol_new cxt_beep_mixer[] = {
HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
- { } /* end */
};
-/* create beep controls if needed */
-static int add_beep_ctls(struct hda_codec *codec)
+static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
+ int idx, int dir)
{
- struct conexant_spec *spec = codec->spec;
- int err;
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+ int i;
- if (spec->beep_amp) {
- const struct snd_kcontrol_new *knew;
- for (knew = cxt_beep_mixer; knew->name; knew++) {
- struct snd_kcontrol *kctl;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
- }
+ spec->gen.beep_nid = nid;
+ for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &cxt_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
}
return 0;
}
-#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#define add_beep_ctls(codec) 0
-#endif
-
-/*
- * Automatic parser for CX20641 & co
- */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static void cx_auto_parse_beep(struct hda_codec *codec)
+static int cx_auto_parse_beep(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
hda_nid_t nid;
for_each_hda_codec_node(nid, codec)
- if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
- set_beep_amp(spec, nid, 0, HDA_OUTPUT);
- break;
- }
+ if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
+ return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+ return 0;
}
#else
-#define cx_auto_parse_beep(codec)
+#define cx_auto_parse_beep(codec) 0
#endif
+/*
+ * Automatic parser for CX20641 & co
+ */
+
/* parse EAPDs */
static void cx_auto_parse_eapd(struct hda_codec *codec)
{
@@ -179,21 +160,6 @@ static void cx_auto_vmaster_hook_mute_led(void *private_data, int enabled)
enabled ? 0x00 : 0x02);
}
-static int cx_auto_build_controls(struct hda_codec *codec)
-{
- int err;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- err = add_beep_ctls(codec);
- if (err < 0)
- return err;
-
- return 0;
-}
-
static int cx_auto_init(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -234,7 +200,7 @@ static void cx_auto_free(struct hda_codec *codec)
}
static const struct hda_codec_ops cx_auto_patch_ops = {
- .build_controls = cx_auto_build_controls,
+ .build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = cx_auto_init,
.reboot_notify = cx_auto_reboot_notify,
@@ -343,6 +309,7 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec,
snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
break;
case HDA_FIXUP_ACT_PROBE:
+ WARN_ON(spec->gen.cap_sync_hook);
spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
spec->gen.automute_hook = cxt_update_headset_mode;
break;
@@ -374,7 +341,7 @@ static void cxt_fixup_headset_mic(struct hda_codec *codec,
* control. */
#define update_mic_pin(codec, nid, val) \
- snd_hda_codec_update_cache(codec, nid, 0, \
+ snd_hda_codec_write_cache(codec, nid, 0, \
AC_VERB_SET_PIN_WIDGET_CONTROL, val)
static const struct hda_input_mux olpc_xo_dc_bias = {
@@ -695,16 +662,12 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
}
/* turn on/off mic-mute LED via GPIO per capture hook */
-static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void cxt_gpio_micmute_update(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
- if (ucontrol)
- cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
- ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
+ cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ spec->gen.micmute_led.led_value);
}
@@ -721,11 +684,11 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook;
spec->gpio_led = 0;
spec->mute_led_polarity = 0;
spec->gpio_mute_led_mask = 0x01;
spec->gpio_mic_led_mask = 0x02;
+ snd_hda_gen_add_micmute_led(codec, cxt_gpio_micmute_update);
}
snd_hda_add_verbs(codec, gpio_init);
if (spec->gpio_led)
@@ -1037,7 +1000,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
codec->spec = spec;
codec->patch_ops = cx_auto_patch_ops;
- cx_auto_parse_beep(codec);
cx_auto_parse_eapd(codec);
spec->gen.own_eapd_ctl = 1;
if (spec->dynamic_eapd)
@@ -1097,6 +1059,10 @@ static int patch_conexant_auto(struct hda_codec *codec)
if (err < 0)
goto error;
+ err = cx_auto_parse_beep(codec);
+ if (err < 0)
+ goto error;
+
/* Some laptops with Conexant chips show stalls in S3 resume,
* which falls into the single-cmd mode.
* Better to make reset, then.
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8a49415aebac..5595b24df18c 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -2498,7 +2498,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
return;
/* ditto during suspend/resume process itself */
- if (atomic_read(&(codec)->core.in_pm))
+ if (snd_hdac_is_in_pm(&codec->core))
return;
snd_hdac_i915_set_bclk(&codec->bus->core);
@@ -2551,6 +2551,8 @@ static int alloc_intel_hdmi(struct hda_codec *codec)
/* requires i915 binding */
if (!codec->bus->core.audio_component) {
codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+ /* set probe_id here to prevent generic fallback binding */
+ codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
return -ENODEV;
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b8a21ff8e68c..db625d00637b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -43,11 +43,9 @@
/* extra amp-initialization sequence types */
enum {
+ ALC_INIT_UNDEFINED,
ALC_INIT_NONE,
ALC_INIT_DEFAULT,
- ALC_INIT_GPIO1,
- ALC_INIT_GPIO2,
- ALC_INIT_GPIO3,
};
enum {
@@ -85,19 +83,20 @@ struct alc_spec {
struct hda_gen_spec gen; /* must be at head */
/* codec parameterization */
- const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
- unsigned int num_mixers;
- unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
-
struct alc_customize_define cdefine;
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+ /* GPIO bits */
+ unsigned int gpio_mask;
+ unsigned int gpio_dir;
+ unsigned int gpio_data;
+ bool gpio_write_delay; /* add a delay before writing gpio_data */
+
/* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */
int mute_led_polarity;
hda_nid_t mute_led_nid;
hda_nid_t cap_mute_led_nid;
- unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
unsigned int gpio_mute_led_mask;
unsigned int gpio_mic_led_mask;
@@ -205,41 +204,87 @@ static void alc_process_coef_fw(struct hda_codec *codec,
}
/*
- * Append the given mixer and verb elements for the later use
- * The mixer array is referred in build_controls(), and init_verbs are
- * called in init().
+ * GPIO setup tables, used in initialization
*/
-static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
+
+/* Enable GPIO mask and set output */
+static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->gpio_mask |= mask;
+ spec->gpio_dir |= mask;
+ spec->gpio_data |= mask;
+}
+
+static void alc_write_gpio_data(struct hda_codec *codec)
{
- if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
+ struct alc_spec *spec = codec->spec;
+
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+}
+
+static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+ bool on)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int oldval = spec->gpio_data;
+
+ if (on)
+ spec->gpio_data |= mask;
+ else
+ spec->gpio_data &= ~mask;
+ if (oldval != spec->gpio_data)
+ alc_write_gpio_data(codec);
+}
+
+static void alc_write_gpio(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->gpio_mask)
return;
- spec->mixers[spec->num_mixers++] = mix;
+
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
+ if (spec->gpio_write_delay)
+ msleep(1);
+ alc_write_gpio_data(codec);
}
-/*
- * GPIO setup tables, used in initialization
- */
-/* Enable GPIO mask and set output */
-static const struct hda_verb alc_gpio1_init_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- { }
-};
+static void alc_fixup_gpio(struct hda_codec *codec, int action,
+ unsigned int mask)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ alc_setup_gpio(codec, mask);
+}
-static const struct hda_verb alc_gpio2_init_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
- { }
-};
+static void alc_fixup_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x01);
+}
-static const struct hda_verb alc_gpio3_init_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
- { }
-};
+static void alc_fixup_gpio2(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x02);
+}
+
+static void alc_fixup_gpio3(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x03);
+}
+
+static void alc_fixup_gpio4(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x04);
+}
/*
* Fix hardware PLL issue
@@ -447,16 +492,8 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
{
alc_fill_eapd_coef(codec);
alc_auto_setup_eapd(codec, true);
+ alc_write_gpio(codec);
switch (type) {
- case ALC_INIT_GPIO1:
- snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
- break;
- case ALC_INIT_GPIO2:
- snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
- break;
- case ALC_INIT_GPIO3:
- snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
- break;
case ALC_INIT_DEFAULT:
switch (codec->core.vendor_id) {
case 0x10ec0260:
@@ -656,20 +693,22 @@ do_sku:
* 7~6 : Reserved
*/
tmp = (ass & 0x38) >> 3; /* external Amp control */
- switch (tmp) {
- case 1:
- spec->init_amp = ALC_INIT_GPIO1;
- break;
- case 3:
- spec->init_amp = ALC_INIT_GPIO2;
- break;
- case 7:
- spec->init_amp = ALC_INIT_GPIO3;
- break;
- case 5:
- default:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
+ if (spec->init_amp == ALC_INIT_UNDEFINED) {
+ switch (tmp) {
+ case 1:
+ alc_setup_gpio(codec, 0x01);
+ break;
+ case 3:
+ alc_setup_gpio(codec, 0x02);
+ break;
+ case 7:
+ alc_setup_gpio(codec, 0x03);
+ break;
+ case 5:
+ default:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
+ }
}
/* is laptop or Desktop and enable the function "Mute internal speaker
@@ -722,47 +761,14 @@ static void alc_fixup_inv_dmic(struct hda_codec *codec,
}
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new alc_beep_mixer[] = {
- HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
- HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
- { } /* end */
-};
-#endif
-
static int alc_build_controls(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int i, err;
+ int err;
err = snd_hda_gen_build_controls(codec);
if (err < 0)
return err;
- for (i = 0; i < spec->num_mixers; i++) {
- err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
- if (err < 0)
- return err;
- }
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
- /* create beep controls if needed */
- if (spec->beep_amp) {
- const struct snd_kcontrol_new *knew;
- for (knew = alc_beep_mixer; knew->name; knew++) {
- struct snd_kcontrol *kctl;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
- }
- }
-#endif
-
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
return 0;
}
@@ -973,8 +979,30 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
* Digital-beep handlers
*/
#ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define set_beep_amp(spec, nid, idx, dir) \
- ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
+ HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+ HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
+};
+
+/* set up and create beep controls */
+static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
+ int idx, int dir)
+{
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &alc_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
+ }
+ return 0;
+}
static const struct snd_pci_quirk beep_white_list[] = {
SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
@@ -999,7 +1027,7 @@ static inline int has_cdefine_beep(struct hda_codec *codec)
return spec->cdefine.enable_pcbeep;
}
#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#define set_beep_amp(spec, nid, idx, dir) 0
#define has_cdefine_beep(codec) 0
#endif
@@ -1104,12 +1132,12 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec,
static const struct hda_fixup alc880_fixups[] = {
[ALC880_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
},
[ALC880_FIXUP_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio2_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio2,
},
[ALC880_FIXUP_MEDION_RIM] = {
.type = HDA_FIXUP_VERBS,
@@ -1501,8 +1529,11 @@ static int patch_alc880(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -1544,8 +1575,8 @@ enum {
static void alc260_gpio1_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gen.hp_jack_present);
+
+ alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
}
static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
@@ -1562,7 +1593,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
snd_hda_jack_detect_enable_callback(codec, 0x0f,
snd_hda_gen_hp_automute);
- snd_hda_add_verbs(codec, alc_gpio1_init_verbs);
+ alc_setup_gpio(codec, 0x01);
}
}
@@ -1589,8 +1620,6 @@ static void alc260_fixup_kn1(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
snd_hda_apply_pincfgs(codec, pincfgs);
- break;
- case HDA_FIXUP_ACT_PROBE:
spec->init_amp = ALC_INIT_NONE;
break;
}
@@ -1600,7 +1629,7 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PROBE)
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
spec->init_amp = ALC_INIT_NONE;
}
@@ -1638,8 +1667,8 @@ static const struct hda_fixup alc260_fixups[] = {
},
},
[ALC260_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
},
[ALC260_FIXUP_GPIO1_TOGGLE] = {
.type = HDA_FIXUP_FUNC,
@@ -1751,8 +1780,11 @@ static int patch_alc260(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -1824,47 +1856,14 @@ static void alc889_fixup_coef(struct hda_codec *codec,
alc_update_coef_idx(codec, 7, 0, 0x2030);
}
-/* toggle speaker-output according to the hp-jack state */
-static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
-{
- unsigned int gpiostate, gpiomask, gpiodir;
-
- gpiostate = snd_hda_codec_read(codec, codec->core.afg, 0,
- AC_VERB_GET_GPIO_DATA, 0);
-
- if (!muted)
- gpiostate |= (1 << pin);
- else
- gpiostate &= ~(1 << pin);
-
- gpiomask = snd_hda_codec_read(codec, codec->core.afg, 0,
- AC_VERB_GET_GPIO_MASK, 0);
- gpiomask |= (1 << pin);
-
- gpiodir = snd_hda_codec_read(codec, codec->core.afg, 0,
- AC_VERB_GET_GPIO_DIRECTION, 0);
- gpiodir |= (1 << pin);
-
-
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_MASK, gpiomask);
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, gpiodir);
-
- msleep(1);
-
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_DATA, gpiostate);
-}
-
/* set up GPIO at initialization */
static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- if (action != HDA_FIXUP_ACT_INIT)
- return;
- alc882_gpio_mute(codec, 0, 0);
- alc882_gpio_mute(codec, 1, 0);
+ struct alc_spec *spec = codec->spec;
+
+ spec->gpio_write_delay = true;
+ alc_fixup_gpio3(codec, fix, action);
}
/* Fix the connection of some pins for ALC889:
@@ -2143,20 +2142,20 @@ static const struct hda_fixup alc882_fixups[] = {
}
},
[ALC882_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
},
[ALC882_FIXUP_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio2_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio2,
},
[ALC882_FIXUP_GPIO3] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio3_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio3,
},
[ALC882_FIXUP_ASUS_W2JC] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
.chained = true,
.chain_id = ALC882_FIXUP_EAPD,
},
@@ -2375,12 +2374,37 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
};
static const struct hda_model_fixup alc882_fixup_models[] = {
+ {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
+ {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
+ {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
+ {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
+ {.id = ALC889_FIXUP_CD, .name = "cd"},
+ {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
+ {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
+ {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
+ {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
+ {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
+ {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
+ {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
+ {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
+ {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
+ {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
+ {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
+ {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
+ {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
+ {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
+ {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
+ {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
+ {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
+ {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+ {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
{.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+ {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
{}
};
@@ -2434,8 +2458,11 @@ static int patch_alc882(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog && spec->gen.beep_nid)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -2556,6 +2583,14 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
static const struct hda_model_fixup alc262_fixup_models[] = {
{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
+ {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
+ {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
+ {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
+ {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
+ {.id = ALC262_FIXUP_BENQ, .name = "benq"},
+ {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
+ {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
{}
};
@@ -2597,8 +2632,11 @@ static int patch_alc262(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog && spec->gen.beep_nid)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -2644,7 +2682,6 @@ static const struct snd_kcontrol_new alc268_beep_mixer[] = {
.put = alc268_beep_switch_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
},
- { }
};
/* set PCBEEP vol = 0, mute connections */
@@ -2685,6 +2722,7 @@ static const struct hda_fixup alc268_fixups[] = {
static const struct hda_model_fixup alc268_fixup_models[] = {
{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
{.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
+ {.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
{}
};
@@ -2712,7 +2750,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
static int patch_alc268(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err;
+ int i, err;
/* ALC268 has no aa-loopback mixer */
err = alc_alloc_spec(codec, 0);
@@ -2734,7 +2772,13 @@ static int patch_alc268(struct hda_codec *codec)
if (err > 0 && !spec->gen.no_analog &&
spec->gen.autocfg.speaker_pins[0] != 0x1d) {
- add_mixer(spec, alc268_beep_mixer);
+ for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &alc268_beep_mixer[i])) {
+ err = -ENOMEM;
+ goto error;
+ }
+ }
snd_hda_add_verbs(codec, alc268_beep_init_verbs);
if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
/* override the amp caps for beep generator */
@@ -3453,9 +3497,8 @@ static int alc269_resume(struct hda_codec *codec)
* suspend, and won't restore the data after resume, so we restore it
* in the driver.
*/
- if (spec->gpio_led)
- snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
+ if (spec->gpio_data)
+ alc_write_gpio_data(codec);
if (spec->has_alc5505_dsp)
alc5505_dsp_resume(codec);
@@ -3695,18 +3738,10 @@ static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
bool enabled)
{
struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_led;
if (spec->mute_led_polarity)
enabled = !enabled;
-
- if (enabled)
- spec->gpio_led &= ~mask;
- else
- spec->gpio_led |= mask;
- if (spec->gpio_led != oldval)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
+ alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
}
/* turn on/off mute LED via GPIO per vmaster hook */
@@ -3719,104 +3754,79 @@ static void alc_fixup_gpio_mute_hook(void *private_data, int enabled)
}
/* turn on/off mic-mute LED via GPIO per capture hook */
-static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void alc_gpio_micmute_update(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (ucontrol)
- alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
- ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
+ alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ spec->gen.micmute_led.led_value);
}
-static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+/* setup mute and mic-mute GPIO bits, add hooks appropriately */
+static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+ int action,
+ unsigned int mute_mask,
+ unsigned int micmute_mask)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
- {}
- };
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ if (mute_mask) {
+ spec->gpio_mute_led_mask = mute_mask;
spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
- spec->gpio_mic_led_mask = 0x10;
- snd_hda_add_verbs(codec, gpio_init);
+ }
+ if (micmute_mask) {
+ spec->gpio_mic_led_mask = micmute_mask;
+ snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update);
}
}
-static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
+}
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x02;
- spec->gpio_mic_led_mask = 0x20;
- snd_hda_add_verbs(codec, gpio_init);
- }
+static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20);
}
/* turn on/off mic-mute LED per capture hook */
-static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void alc_cap_micmute_update(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- unsigned int pinval, enable, disable;
+ unsigned int pinval;
+ if (!spec->cap_mute_led_nid)
+ return;
pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid);
pinval &= ~AC_PINCTL_VREFEN;
- enable = pinval | AC_PINCTL_VREF_80;
- disable = pinval | AC_PINCTL_VREF_HIZ;
-
- if (!ucontrol)
- return;
-
- if (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1])
- pinval = disable;
+ if (spec->gen.micmute_led.led_value)
+ pinval |= AC_PINCTL_VREF_80;
else
- pinval = enable;
-
- if (spec->cap_mute_led_nid)
- snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval);
+ pinval |= AC_PINCTL_VREF_HIZ;
+ snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval);
}
static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x08 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x08 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
+ /* Like hp_gpio_mic1_led, but also needs GPIO4 low to
+ * enable headphone amp
+ */
+ spec->gpio_mask |= 0x10;
+ spec->gpio_dir |= 0x10;
spec->cap_mute_led_nid = 0x18;
- snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update);
codec->power_filter = led_power_filter;
}
}
@@ -3824,22 +3834,12 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- /* Like hp_gpio_mic1_led, but also needs GPIO4 low to enable headphone amp */
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
spec->cap_mute_led_nid = 0x18;
- snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update);
codec->power_filter = led_power_filter;
}
}
@@ -3889,38 +3889,29 @@ static int alc_register_micmute_input_device(struct hda_codec *codec)
return 0;
}
+/* GPIO1 = set according to SKU external amp
+ * GPIO2 = mic mute hotkey
+ * GPIO3 = mute LED
+ * GPIO4 = mic mute LED
+ */
static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- /* GPIO1 = set according to SKU external amp
- GPIO2 = mic mute hotkey
- GPIO3 = mute LED
- GPIO4 = mic mute LED */
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
- { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
- {}
- };
-
struct alc_spec *spec = codec->spec;
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->init_amp = ALC_INIT_DEFAULT;
if (alc_register_micmute_input_device(codec) != 0)
return;
- snd_hda_add_verbs(codec, gpio_init);
+ spec->gpio_mask |= 0x06;
+ spec->gpio_dir |= 0x02;
+ spec->gpio_data |= 0x02;
snd_hda_codec_write_cache(codec, codec->core.afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
gpio2_mic_hotkey_event);
-
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
- spec->gpio_mic_led_mask = 0x10;
return;
}
@@ -3928,40 +3919,28 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
return;
switch (action) {
- case HDA_FIXUP_ACT_PROBE:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
case HDA_FIXUP_ACT_FREE:
input_unregister_device(spec->kb_dev);
spec->kb_dev = NULL;
}
}
+/* Line2 = mic mute hotkey
+ * GPIO2 = mic mute LED
+ */
static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- /* Line2 = mic mute hotkey
- GPIO2 = mic mute LED */
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
- {}
- };
-
struct alc_spec *spec = codec->spec;
+ alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->init_amp = ALC_INIT_DEFAULT;
if (alc_register_micmute_input_device(codec) != 0)
return;
- snd_hda_add_verbs(codec, gpio_init);
snd_hda_jack_detect_enable_callback(codec, 0x1b,
gpio2_mic_hotkey_event);
-
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mic_led_mask = 0x04;
return;
}
@@ -3969,9 +3948,6 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
return;
switch (action) {
- case HDA_FIXUP_ACT_PROBE:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
case HDA_FIXUP_ACT_FREE:
input_unregister_device(spec->kb_dev);
spec->kb_dev = NULL;
@@ -3987,14 +3963,10 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
{
struct alc_spec *spec = codec->spec;
+ alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1a);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
- spec->mute_led_polarity = 0;
- spec->mute_led_nid = 0x1a;
spec->cap_mute_led_nid = 0x18;
- spec->gen.vmaster_mute_enum = 1;
- codec->power_filter = led_power_filter;
+ snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update);
}
}
@@ -4842,6 +4814,7 @@ static void alc_probe_headset_mode(struct hda_codec *codec)
spec->headphone_mic_pin = cfg->inputs[i].pin;
}
+ WARN_ON(spec->gen.cap_sync_hook);
spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
spec->gen.automute_hook = alc_update_headset_mode;
spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
@@ -4933,13 +4906,10 @@ static void alc288_update_headset_jack_cb(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
struct alc_spec *spec = codec->spec;
- int present;
alc_update_headset_jack_cb(codec, jack);
/* Headset Mic enable or disable, only for Dell Dino */
- present = spec->gen.hp_jack_present ? 0x40 : 0;
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- present);
+ alc_update_gpio_data(codec, 0x40, spec->gen.hp_jack_present);
}
static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
@@ -4948,6 +4918,9 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
alc_fixup_headset_mode(codec, fix, action);
if (action == HDA_FIXUP_ACT_PROBE) {
struct alc_spec *spec = codec->spec;
+ /* toggled via hp_automute_hook */
+ spec->gpio_mask |= 0x40;
+ spec->gpio_dir |= 0x40;
spec->gen.hp_automute_hook = alc288_update_headset_jack_cb;
}
}
@@ -4968,7 +4941,7 @@ static void alc_no_shutup(struct hda_codec *codec)
static void alc_fixup_no_shutup(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- if (action == HDA_FIXUP_ACT_PROBE) {
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct alc_spec *spec = codec->spec;
spec->shutup = alc_no_shutup;
}
@@ -5050,10 +5023,9 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec,
* it causes a click noise at start up
*/
snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+ spec->shutup = alc_shutup_dell_xps13;
break;
case HDA_FIXUP_ACT_PROBE:
- spec->shutup = alc_shutup_dell_xps13;
-
/* Make the internal mic the default input source. */
for (i = 0; i < imux->num_items; i++) {
if (spec->gen.imux_pins[i] == 0x12) {
@@ -5230,13 +5202,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- /* TX300 needs to set up GPIO2 for the speaker amp */
- static const struct hda_verb gpio2_verbs[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
- {}
- };
static const struct hda_pintbl dock_pins[] = {
{ 0x1b, 0x21114000 }, /* dock speaker pin */
{}
@@ -5244,13 +5209,18 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
- snd_hda_add_verbs(codec, gpio2_verbs);
+ spec->init_amp = ALC_INIT_DEFAULT;
+ /* TX300 needs to set up GPIO2 for the speaker amp */
+ alc_setup_gpio(codec, 0x04);
snd_hda_apply_pincfgs(codec, dock_pins);
spec->gen.auto_mute_via_amp = 1;
spec->gen.automute_hook = asus_tx300_automute;
snd_hda_jack_detect_enable_callback(codec, 0x1b,
snd_hda_gen_hp_automute);
break;
+ case HDA_FIXUP_ACT_PROBE:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
case HDA_FIXUP_ACT_BUILD:
/* this is a bit tricky; give more sane names for the main
* (tablet) speaker and the dock speaker, respectively
@@ -5324,30 +5294,26 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec,
int action)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- /* Set the hooks to turn the headphone amp on/off
- * as needed
- */
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ /* amp at GPIO4; toggled via alc280_hp_gpio4_automute_hook() */
+ spec->gpio_mask |= 0x10;
+ spec->gpio_dir |= 0x10;
spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook;
+ }
+}
- /* The GPIOs are currently off */
- spec->gpio_led = 0;
-
- /* GPIO3 is connected to the output mute LED,
- * high is on, low is off
- */
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
+static void alc275_fixup_gpio4_off(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct alc_spec *spec = codec->spec;
- /* Initialize GPIO configuration */
- snd_hda_add_verbs(codec, gpio_init);
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gpio_mask |= 0x04;
+ spec->gpio_dir |= 0x04;
+ /* set data bit low */
}
}
@@ -5491,7 +5457,6 @@ enum {
ALC280_FIXUP_HP_9480M,
ALC288_FIXUP_DELL_HEADSET_MODE,
ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
- ALC288_FIXUP_DELL_XPS_13_GPIO6,
ALC288_FIXUP_DELL_XPS_13,
ALC288_FIXUP_DISABLE_AAMIX,
ALC292_FIXUP_DELL_E7X,
@@ -5539,13 +5504,8 @@ static const struct hda_fixup alc269_fixups[] = {
}
},
[ALC275_FIXUP_SONY_VAIO_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- { }
- },
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc275_fixup_gpio4_off,
.chained = true,
.chain_id = ALC269_FIXUP_SONY_VAIO
},
@@ -6112,22 +6072,11 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC288_FIXUP_DELL_HEADSET_MODE
},
- [ALC288_FIXUP_DELL_XPS_13_GPIO6] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x40},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x40},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- { }
- },
- .chained = true,
- .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
- },
[ALC288_FIXUP_DISABLE_AAMIX] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_disable_aamix,
.chained = true,
- .chain_id = ALC288_FIXUP_DELL_XPS_13_GPIO6
+ .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
},
[ALC288_FIXUP_DELL_XPS_13] = {
.type = HDA_FIXUP_FUNC,
@@ -6290,14 +6239,9 @@ static const struct hda_fixup alc269_fixups[] = {
.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
},
[ALC256_FIXUP_ASUS_AIO_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* Set up GPIO2 for the speaker amp */
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
- {}
- },
+ .type = HDA_FIXUP_FUNC,
+ /* Set up GPIO2 for the speaker amp */
+ .v.func = alc_fixup_gpio4,
},
[ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
@@ -6712,13 +6656,95 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic1-led"},
{.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
{.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
+ {.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"},
+ {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"},
{.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
{.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
{.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
{.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
{.id = ALC292_FIXUP_TPT460, .name = "tpt460"},
+ {.id = ALC298_FIXUP_TPT470_DOCK, .name = "tpt470-dock"},
{.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
{.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"},
+ {.id = ALC269_FIXUP_SONY_VAIO, .name = "vaio"},
+ {.id = ALC269_FIXUP_DELL_M101Z, .name = "dell-m101z"},
+ {.id = ALC269_FIXUP_ASUS_G73JW, .name = "asus-g73jw"},
+ {.id = ALC269_FIXUP_LENOVO_EAPD, .name = "lenovo-eapd"},
+ {.id = ALC275_FIXUP_SONY_HWEQ, .name = "sony-hweq"},
+ {.id = ALC269_FIXUP_PCM_44K, .name = "pcm44k"},
+ {.id = ALC269_FIXUP_LIFEBOOK, .name = "lifebook"},
+ {.id = ALC269_FIXUP_LIFEBOOK_EXTMIC, .name = "lifebook-extmic"},
+ {.id = ALC269_FIXUP_LIFEBOOK_HP_PIN, .name = "lifebook-hp-pin"},
+ {.id = ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC, .name = "lifebook-u7x7"},
+ {.id = ALC269VB_FIXUP_AMIC, .name = "alc269vb-amic"},
+ {.id = ALC269VB_FIXUP_DMIC, .name = "alc269vb-dmic"},
+ {.id = ALC269_FIXUP_HP_MUTE_LED_MIC1, .name = "hp-mute-led-mic1"},
+ {.id = ALC269_FIXUP_HP_MUTE_LED_MIC2, .name = "hp-mute-led-mic2"},
+ {.id = ALC269_FIXUP_HP_MUTE_LED_MIC3, .name = "hp-mute-led-mic3"},
+ {.id = ALC269_FIXUP_HP_GPIO_MIC1_LED, .name = "hp-gpio-mic1"},
+ {.id = ALC269_FIXUP_HP_LINE1_MIC1_LED, .name = "hp-line1-mic1"},
+ {.id = ALC269_FIXUP_NO_SHUTUP, .name = "noshutup"},
+ {.id = ALC286_FIXUP_SONY_MIC_NO_PRESENCE, .name = "sony-nomic"},
+ {.id = ALC269_FIXUP_ASPIRE_HEADSET_MIC, .name = "aspire-headset-mic"},
+ {.id = ALC269_FIXUP_ASUS_X101, .name = "asus-x101"},
+ {.id = ALC271_FIXUP_HP_GATE_MIC_JACK, .name = "acer-ao7xx"},
+ {.id = ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, .name = "acer-aspire-e1"},
+ {.id = ALC269_FIXUP_ACER_AC700, .name = "acer-ac700"},
+ {.id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, .name = "limit-mic-boost"},
+ {.id = ALC269VB_FIXUP_ASUS_ZENBOOK, .name = "asus-zenbook"},
+ {.id = ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, .name = "asus-zenbook-ux31a"},
+ {.id = ALC269VB_FIXUP_ORDISSIMO_EVE2, .name = "ordissimo"},
+ {.id = ALC282_FIXUP_ASUS_TX300, .name = "asus-tx300"},
+ {.id = ALC283_FIXUP_INT_MIC, .name = "alc283-int-mic"},
+ {.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"},
+ {.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"},
+ {.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"},
+ {.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"},
+ {.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"},
+ {.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"},
+ {.id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"},
+ {.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
+ {.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
+ {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
+ {.id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, .name = "alc255-dell-mute"},
+ {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
+ {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
+ {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
+ {.id = ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, .name = "hp-gpio2-hotkey"},
+ {.id = ALC280_FIXUP_HP_DOCK_PINS, .name = "hp-dock-pins"},
+ {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic"},
+ {.id = ALC280_FIXUP_HP_9480M, .name = "hp-9480m"},
+ {.id = ALC288_FIXUP_DELL_HEADSET_MODE, .name = "alc288-dell-headset"},
+ {.id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc288-dell1"},
+ {.id = ALC288_FIXUP_DELL_XPS_13, .name = "alc288-dell-xps13"},
+ {.id = ALC292_FIXUP_DELL_E7X, .name = "dell-e7x"},
+ {.id = ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, .name = "alc293-dell"},
+ {.id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc298-dell1"},
+ {.id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, .name = "alc298-dell-aio"},
+ {.id = ALC275_FIXUP_DELL_XPS, .name = "alc275-dell-xps"},
+ {.id = ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, .name = "alc256-dell-xps13"},
+ {.id = ALC293_FIXUP_LENOVO_SPK_NOISE, .name = "lenovo-spk-noise"},
+ {.id = ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, .name = "lenovo-hotkey"},
+ {.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"},
+ {.id = ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"},
+ {.id = ALC295_FIXUP_DISABLE_DAC3, .name = "alc295-disable-dac3"},
+ {.id = ALC280_FIXUP_HP_HEADSET_MIC, .name = "alc280-hp-headset"},
+ {.id = ALC221_FIXUP_HP_FRONT_MIC, .name = "alc221-hp-mic"},
+ {.id = ALC298_FIXUP_SPK_VOLUME, .name = "alc298-spk-volume"},
+ {.id = ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, .name = "dell-inspiron-7559"},
+ {.id = ALC269_FIXUP_ATIV_BOOK_8, .name = "ativ-book"},
+ {.id = ALC221_FIXUP_HP_MIC_NO_PRESENCE, .name = "alc221-hp-mic"},
+ {.id = ALC256_FIXUP_ASUS_HEADSET_MODE, .name = "alc256-asus-headset"},
+ {.id = ALC256_FIXUP_ASUS_MIC, .name = "alc256-asus-mic"},
+ {.id = ALC256_FIXUP_ASUS_AIO_GPIO2, .name = "alc256-asus-aio"},
+ {.id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc233-asus"},
+ {.id = ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, .name = "alc233-eapd"},
+ {.id = ALC294_FIXUP_LENOVO_MIC_LOCATION, .name = "alc294-lenovo-mic"},
+ {.id = ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, .name = "alc225-wyse"},
+ {.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
+ {.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
+ {.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
+ {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
{}
};
#define ALC225_STANDARD_PINS \
@@ -6982,7 +7008,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x12, 0x90a60130},
{0x19, 0x03a11020},
{0x21, 0x0321101f}),
- SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL_XPS_13_GPIO6,
+ SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60120},
{0x14, 0x90170110},
{0x21, 0x0321101f}),
@@ -7139,18 +7165,6 @@ static int patch_alc269(struct hda_codec *codec)
spec->shutup = alc_default_shutup;
spec->init_hook = alc_default_init;
- snd_hda_pick_fixup(codec, alc269_fixup_models,
- alc269_fixup_tbl, alc269_fixups);
- snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups);
- snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
- alc269_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- alc_auto_parse_customize_define(codec);
-
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x01;
-
switch (codec->core.vendor_id) {
case 0x10ec0269:
spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -7270,13 +7284,28 @@ static int patch_alc269(struct hda_codec *codec)
spec->init_hook = alc5505_dsp_init;
}
+ snd_hda_pick_fixup(codec, alc269_fixup_models,
+ alc269_fixup_tbl, alc269_fixups);
+ snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups);
+ snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
+ alc269_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ alc_auto_parse_customize_define(codec);
+
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x01;
+
/* automatic parse from the BIOS config */
err = alc269_parse_auto_config(codec);
if (err < 0)
goto error;
- if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid)
- set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT);
+ if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) {
+ err = set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7405,8 +7434,11 @@ static int patch_alc861(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7446,16 +7478,21 @@ static void alc861vd_fixup_dallas(struct hda_codec *codec,
}
}
+/* reset GPIO1 */
+static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->gpio_mask |= 0x02;
+ alc_fixup_gpio(codec, action, 0x01);
+}
+
static const struct hda_fixup alc861vd_fixups[] = {
[ALC660VD_FIX_ASUS_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* reset GPIO1 */
- {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- { }
- }
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc660vd_fixup_asus_gpio1,
},
[ALC861VD_FIX_DALLAS] = {
.type = HDA_FIXUP_FUNC,
@@ -7494,8 +7531,11 @@ static int patch_alc861vd(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7576,7 +7616,7 @@ static unsigned int gpio_led_power_filter(struct hda_codec *codec,
unsigned int power_state)
{
struct alc_spec *spec = codec->spec;
- if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_led)
+ if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
return AC_PWRST_D0;
return power_state;
}
@@ -7585,18 +7625,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gpio_led = 0;
spec->mute_led_polarity = 1;
- spec->gpio_mute_led_mask = 0x01;
- snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = gpio_led_power_filter;
}
}
@@ -8109,7 +8141,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
};
static const struct hda_model_fixup alc662_fixup_models[] = {
+ {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
+ {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
{.id = ALC272_FIXUP_MARIO, .name = "mario"},
+ {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
@@ -8118,8 +8153,23 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
+ {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+ {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
+ {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
+ {.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
+ {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
+ {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
+ {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
+ {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
+ {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+ {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
+ {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
+ {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
+ {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
+ {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
{}
};
@@ -8213,18 +8263,20 @@ static int patch_alc662(struct hda_codec *codec)
if (!spec->gen.no_analog && spec->gen.beep_nid) {
switch (codec->core.vendor_id) {
case 0x10ec0662:
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
break;
case 0x10ec0272:
case 0x10ec0663:
case 0x10ec0665:
case 0x10ec0668:
- set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+ err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
break;
case 0x10ec0273:
- set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+ err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
break;
}
+ if (err < 0)
+ goto error;
}
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 63d15b545b33..046705b4691a 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -332,33 +332,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
}
/* hook for controlling mic-mute LED GPIO */
-static void stac_capture_led_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void stac_capture_led_update(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- unsigned int mask;
- bool cur_mute, prev_mute;
- if (!kcontrol || !ucontrol)
- return;
-
- mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- prev_mute = !spec->mic_enabled;
- if (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1])
- spec->mic_enabled |= mask;
+ if (spec->gen.micmute_led.led_value)
+ spec->gpio_data |= spec->mic_mute_led_gpio;
else
- spec->mic_enabled &= ~mask;
- cur_mute = !spec->mic_enabled;
- if (cur_mute != prev_mute) {
- if (cur_mute)
- spec->gpio_data |= spec->mic_mute_led_gpio;
- else
- spec->gpio_data &= ~spec->mic_mute_led_gpio;
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data);
- }
+ spec->gpio_data &= ~spec->mic_mute_led_gpio;
+ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
}
static int stac_vrefout_set(struct hda_codec *codec,
@@ -4656,8 +4638,7 @@ static void stac_setup_gpio(struct hda_codec *codec)
spec->gpio_dir |= spec->mic_mute_led_gpio;
spec->mic_enabled = 0;
spec->gpio_data |= spec->mic_mute_led_gpio;
-
- spec->gen.cap_sync_hook = stac_capture_led_hook;
+ snd_hda_gen_add_micmute_led(codec, stac_capture_led_update);
}
}
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index fc30d1e8aa76..6b9617aee0e6 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -90,13 +90,6 @@ enum VIA_HDA_CODEC {
struct via_spec {
struct hda_gen_spec gen;
- /* codec parameterization */
- const struct snd_kcontrol_new *mixers[6];
- unsigned int num_mixers;
-
- const struct hda_verb *init_verbs[5];
- unsigned int num_iverbs;
-
/* HP mode source */
unsigned int dmic_enabled;
enum VIA_HDA_CODEC codec_type;
@@ -107,8 +100,6 @@ struct via_spec {
/* work to check hp jack state */
int hp_work_active;
int vt1708_jack_detect;
-
- unsigned int beep_amp;
};
static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
@@ -262,69 +253,51 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct snd_kcontrol_new via_pin_power_ctl_enum[] = {
- {
+static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Dynamic Power-Control",
.info = via_pin_power_ctl_info,
.get = via_pin_power_ctl_get,
.put = via_pin_power_ctl_put,
- },
- {} /* terminator */
};
#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static inline void set_beep_amp(struct via_spec *spec, hda_nid_t nid,
- int idx, int dir)
-{
- spec->gen.beep_nid = nid;
- spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-}
-
/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new cxt_beep_mixer[] = {
+static const struct snd_kcontrol_new via_beep_mixer[] = {
HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
- { } /* end */
};
-/* create beep controls if needed */
-static int add_beep_ctls(struct hda_codec *codec)
+static int set_beep_amp(struct via_spec *spec, hda_nid_t nid,
+ int idx, int dir)
{
- struct via_spec *spec = codec->spec;
- int err;
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+ int i;
- if (spec->beep_amp) {
- const struct snd_kcontrol_new *knew;
- for (knew = cxt_beep_mixer; knew->name; knew++) {
- struct snd_kcontrol *kctl;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
- }
+ spec->gen.beep_nid = nid;
+ for (i = 0; i < ARRAY_SIZE(via_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &via_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
}
return 0;
}
-static void auto_parse_beep(struct hda_codec *codec)
+static int auto_parse_beep(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
hda_nid_t nid;
for_each_hda_codec_node(nid, codec)
- if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
- set_beep_amp(spec, nid, 0, HDA_OUTPUT);
- break;
- }
+ if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
+ return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+ return 0;
}
#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#define add_beep_ctls(codec) 0
-#define auto_parse_beep(codec)
+#define auto_parse_beep(codec) 0
#endif
/* check AA path's mute status */
@@ -403,30 +376,6 @@ static void analog_low_current_mode(struct hda_codec *codec)
return __analog_low_current_mode(codec, false);
}
-static int via_build_controls(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err, i;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- err = add_beep_ctls(codec);
- if (err < 0)
- return err;
-
- spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
-
- for (i = 0; i < spec->num_mixers; i++) {
- err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream,
@@ -481,7 +430,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
static int via_init(struct hda_codec *codec);
static const struct hda_codec_ops via_patch_ops = {
- .build_controls = via_build_controls,
+ .build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = via_init,
.free = via_free,
@@ -545,16 +494,13 @@ static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = {
- {
+static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Jack Detect",
.count = 1,
.info = snd_ctl_boolean_mono_info,
.get = vt1708_jack_detect_get,
.put = vt1708_jack_detect_put,
- },
- {} /* terminator */
};
static const struct badness_table via_main_out_badness = {
@@ -586,12 +532,17 @@ static int via_parse_auto_config(struct hda_codec *codec)
if (err < 0)
return err;
- auto_parse_beep(codec);
-
err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
if (err < 0)
return err;
+ err = auto_parse_beep(codec);
+ if (err < 0)
+ return err;
+
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &via_pin_power_ctl_enum))
+ return -ENOMEM;
+
/* disable widget PM at start for compatibility */
codec->power_save_node = 0;
spec->gen.power_down_unused = 0;
@@ -600,12 +551,6 @@ static int via_parse_auto_config(struct hda_codec *codec)
static int via_init(struct hda_codec *codec)
{
- struct via_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->num_iverbs; i++)
- snd_hda_sequence_write(codec, spec->init_verbs[i]);
-
/* init power states */
__analog_low_current_mode(codec, true);
@@ -623,7 +568,7 @@ static int vt1708_build_controls(struct hda_codec *codec)
int err;
int old_interval = codec->jackpoll_interval;
codec->jackpoll_interval = msecs_to_jiffies(100);
- err = via_build_controls(codec);
+ err = snd_hda_gen_build_controls(codec);
codec->jackpoll_interval = old_interval;
return err;
}
@@ -684,22 +629,29 @@ static int patch_vt1708(struct hda_codec *codec)
vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+ err = snd_hda_add_verbs(codec, vt1708_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
/* add jack detect on/off control */
- spec->mixers[spec->num_mixers++] = vt1708_jack_detect_ctl;
-
- spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs;
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {
+ err = -ENOMEM;
+ goto error;
+ }
/* clear jackpoll_interval again; it's set dynamically */
codec->jackpoll_interval = 0;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
static int patch_vt1709(struct hda_codec *codec)
@@ -715,12 +667,14 @@ static int patch_vt1709(struct hda_codec *codec)
spec->gen.mixer_nid = 0x18;
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
static int patch_vt1708S(struct hda_codec *codec);
@@ -741,12 +695,14 @@ static int patch_vt1708B(struct hda_codec *codec)
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1708S */
@@ -791,16 +747,20 @@ static int patch_vt1708S(struct hda_codec *codec)
if (codec->core.vendor_id == 0x11064397)
snd_hda_codec_set_name(codec, "VT1705");
+ err = snd_hda_add_verbs(codec, vt1708S_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1702 */
@@ -832,16 +792,20 @@ static int patch_vt1702(struct hda_codec *codec)
(0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
+ err = snd_hda_add_verbs(codec, vt1702_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1718S */
@@ -904,16 +868,20 @@ static int patch_vt1718S(struct hda_codec *codec)
override_mic_boost(codec, 0x29, 0, 3, 40);
add_secret_dac_path(codec);
+ err = snd_hda_add_verbs(codec, vt1718S_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1716S */
@@ -955,9 +923,9 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
- HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
- {
+static const struct snd_kcontrol_new vt1716s_dmic_mixer_vol =
+ HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT);
+static const struct snd_kcontrol_new vt1716s_dmic_mixer_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Mic Capture Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
@@ -965,16 +933,12 @@ static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
.info = vt1716s_dmic_info,
.get = vt1716s_dmic_get,
.put = vt1716s_dmic_put,
- },
- {} /* end */
};
/* mono-out mixer elements */
-static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
- HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
- { } /* end */
-};
+static const struct snd_kcontrol_new vt1716S_mono_out_mixer =
+ HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT);
static const struct hda_verb vt1716S_init_verbs[] = {
/* Enable Boost Volume backdoor */
@@ -1000,19 +964,27 @@ static int patch_vt1716S(struct hda_codec *codec)
override_mic_boost(codec, 0x1a, 0, 3, 40);
override_mic_boost(codec, 0x1e, 0, 3, 40);
+ err = snd_hda_add_verbs(codec, vt1716S_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs;
+ if (err < 0)
+ goto error;
- spec->mixers[spec->num_mixers++] = vt1716s_dmic_mixer;
- spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||
+ !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||
+ !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {
+ err = -ENOMEM;
+ goto error;
+ }
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* for vt2002P */
@@ -1107,19 +1079,23 @@ static int patch_vt2002P(struct hda_codec *codec)
snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- /* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
if (spec->codec_type == VT1802)
- spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs;
+ err = snd_hda_add_verbs(codec, vt1802_init_verbs);
else
- spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs;
+ err = snd_hda_add_verbs(codec, vt2002P_init_verbs);
+ if (err < 0)
+ goto error;
+
+ /* automatic parse from the BIOS config */
+ err = via_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* for vt1812 */
@@ -1148,16 +1124,20 @@ static int patch_vt1812(struct hda_codec *codec)
override_mic_boost(codec, 0x29, 0, 3, 40);
add_secret_dac_path(codec);
+ err = snd_hda_add_verbs(codec, vt1812_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* patch for vt3476 */
@@ -1185,16 +1165,20 @@ static int patch_vt3476(struct hda_codec *codec)
spec->gen.mixer_nid = 0x3f;
add_secret_dac_path(codec);
+ err = snd_hda_add_verbs(codec, vt3476_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/*
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
index 65bb3ac6af4c..97f49b751e6e 100644
--- a/sound/pci/hda/thinkpad_helper.c
+++ b/sound/pci/hda/thinkpad_helper.c
@@ -27,17 +27,11 @@ static void update_tpacpi_mute_led(void *private_data, int enabled)
led_set_func(TPACPI_LED_MUTE, !enabled);
}
-static void update_tpacpi_micmute_led(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void update_tpacpi_micmute(struct hda_codec *codec)
{
- if (!ucontrol || !led_set_func)
- return;
- if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
- /* TODO: How do I verify if it's a mono or stereo here? */
- bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
- led_set_func(TPACPI_LED_MICMUTE, !val);
- }
+ struct hda_gen_spec *spec = codec->spec;
+
+ led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
}
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
@@ -63,15 +57,10 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
spec->vmaster_mute.hook = update_tpacpi_mute_led;
removefunc = false;
}
- if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
- if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
- codec_dbg(codec,
- "Skipping micmute LED control due to several ADCs");
- else {
- spec->cap_sync_hook = update_tpacpi_micmute_led;
- removefunc = false;
- }
- }
+ if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
+ snd_hda_gen_add_micmute_led(codec,
+ update_tpacpi_micmute) > 0)
+ removefunc = false;
}
if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
OpenPOWER on IntegriCloud