diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 81 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 66 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 39 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 136 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 9 | ||||
-rw-r--r-- | sound/pci/hda/hda_trace.h | 26 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 40 |
7 files changed, 297 insertions, 100 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f560051..a6c34dc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4205,7 +4205,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) * * This function returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_build_pcms(struct hda_bus *bus) +int snd_hda_build_pcms(struct hda_bus *bus) { struct hda_codec *codec; @@ -4432,19 +4432,16 @@ void snd_hda_update_power_acct(struct hda_codec *codec) /* Transition to powered up, if wait_power_down then wait for a pending * transition to D3 to complete. A pending D3 transition is indicated * with power_transition == -1. */ +/* call this with codec->power_lock held! */ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) { struct hda_bus *bus = codec->bus; - spin_lock(&codec->power_lock); - codec->power_count++; /* Return if power_on or transitioning to power_on, unless currently * powering down. */ if ((codec->power_on || codec->power_transition > 0) && - !(wait_power_down && codec->power_transition < 0)) { - spin_unlock(&codec->power_lock); + !(wait_power_down && codec->power_transition < 0)) return; - } spin_unlock(&codec->power_lock); cancel_delayed_work_sync(&codec->power_work); @@ -4456,9 +4453,9 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) if (codec->power_on) { if (codec->power_transition < 0) codec->power_transition = 0; - spin_unlock(&codec->power_lock); return; } + trace_hda_power_up(codec); snd_hda_update_power_acct(codec); codec->power_on = 1; @@ -4472,65 +4469,45 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) spin_lock(&codec->power_lock); codec->power_transition = 0; - spin_unlock(&codec->power_lock); -} - -/** - * snd_hda_power_up - Power-up the codec - * @codec: HD-audio codec - * - * Increment the power-up counter and power up the hardware really when - * not turned on yet. - */ -void snd_hda_power_up(struct hda_codec *codec) -{ - __snd_hda_power_up(codec, false); -} -EXPORT_SYMBOL_HDA(snd_hda_power_up); - -/** - * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending - * D3 transition to complete. This differs from snd_hda_power_up() when - * power_transition == -1. snd_hda_power_up sees this case as a nop, - * snd_hda_power_up_d3wait waits for the D3 transition to complete then powers - * back up. - * @codec: HD-audio codec - * - * Cancel any power down operation hapenning on the work queue, then power up. - */ -void snd_hda_power_up_d3wait(struct hda_codec *codec) -{ - /* This will cancel and wait for pending power_work to complete. */ - __snd_hda_power_up(codec, true); } -EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait); #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) -/** - * snd_hda_power_down - Power-down the codec - * @codec: HD-audio codec - * - * Decrement the power-up counter and schedules the power-off work if - * the counter rearches to zero. - */ -void snd_hda_power_down(struct hda_codec *codec) +/* Transition to powered down */ +static void __snd_hda_power_down(struct hda_codec *codec) { - spin_lock(&codec->power_lock); - --codec->power_count; - if (!codec->power_on || codec->power_count || codec->power_transition) { - spin_unlock(&codec->power_lock); + if (!codec->power_on || codec->power_count || codec->power_transition) return; - } + if (power_save(codec)) { codec->power_transition = -1; /* avoid reentrance */ queue_delayed_work(codec->bus->workq, &codec->power_work, msecs_to_jiffies(power_save(codec) * 1000)); } +} + +/** + * snd_hda_power_save - Power-up/down/sync the codec + * @codec: HD-audio codec + * @delta: the counter delta to change + * + * Change the power-up counter via @delta, and power up or down the hardware + * appropriately. For the power-down, queue to the delayed action. + * Passing zero to @delta means to synchronize the power state. + */ +void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) +{ + spin_lock(&codec->power_lock); + codec->power_count += delta; + trace_hda_power_count(codec); + if (delta > 0) + __snd_hda_power_up(codec, d3wait); + else + __snd_hda_power_down(codec); spin_unlock(&codec->power_lock); } -EXPORT_SYMBOL_HDA(snd_hda_power_down); +EXPORT_SYMBOL_HDA(snd_hda_power_save); /** * snd_hda_check_amp_list_power - Check the amp list and update the power diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 7fbc1bc..92ecb2b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -386,6 +386,10 @@ enum { /* DIGITAL2 bits */ #define AC_DIG2_CC (0x7f<<0) +/* DIGITAL3 bits */ +#define AC_DIG3_ICT (0xf<<0) +#define AC_DIG3_KAE (1<<7) + /* Pin widget control - 8bit */ #define AC_PINCTL_EPT (0x3<<0) #define AC_PINCTL_EPT_NATIVE 0 @@ -1059,21 +1063,69 @@ const char *snd_hda_get_jack_location(u32 cfg); * power saving */ #ifdef CONFIG_SND_HDA_POWER_SAVE -void snd_hda_power_up(struct hda_codec *codec); -void snd_hda_power_up_d3wait(struct hda_codec *codec); -void snd_hda_power_down(struct hda_codec *codec); +void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait); void snd_hda_update_power_acct(struct hda_codec *codec); #else -static inline void snd_hda_power_up(struct hda_codec *codec) {} -static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {} -static inline void snd_hda_power_down(struct hda_codec *codec) {} +static inline void snd_hda_power_save(struct hda_codec *codec, int delta, + bool d3wait) {} #endif +/** + * snd_hda_power_up - Power-up the codec + * @codec: HD-audio codec + * + * Increment the power-up counter and power up the hardware really when + * not turned on yet. + */ +static inline void snd_hda_power_up(struct hda_codec *codec) +{ + snd_hda_power_save(codec, 1, false); +} + +/** + * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending + * D3 transition to complete. This differs from snd_hda_power_up() when + * power_transition == -1. snd_hda_power_up sees this case as a nop, + * snd_hda_power_up_d3wait waits for the D3 transition to complete then powers + * back up. + * @codec: HD-audio codec + * + * Cancel any power down operation hapenning on the work queue, then power up. + */ +static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) +{ + snd_hda_power_save(codec, 1, true); +} + +/** + * snd_hda_power_down - Power-down the codec + * @codec: HD-audio codec + * + * Decrement the power-up counter and schedules the power-off work if + * the counter rearches to zero. + */ +static inline void snd_hda_power_down(struct hda_codec *codec) +{ + snd_hda_power_save(codec, -1, false); +} + +/** + * snd_hda_power_sync - Synchronize the power-save status + * @codec: HD-audio codec + * + * Synchronize the actual power state with the power account; + * called when power_save parameter is changed + */ +static inline void snd_hda_power_sync(struct hda_codec *codec) +{ + snd_hda_power_save(codec, 0, false); +} + #ifdef CONFIG_SND_HDA_PATCH_LOADER /* * patch firmware */ -int snd_hda_load_patch(struct hda_bus *bus, const char *patch); +int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf); #endif /* diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6b2efb8..b9a644c 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -25,7 +25,6 @@ #include <linux/mutex.h> #include <linux/ctype.h> #include <linux/string.h> -#include <linux/firmware.h> #include <linux/export.h> #include <sound/core.h> #include "hda_codec.h" @@ -747,18 +746,21 @@ static int parse_line_mode(char *buf, struct hda_bus *bus) * * the spaces at the beginning and the end of the line are stripped */ -static int get_line_from_fw(char *buf, int size, struct firmware *fw) +static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, + const void **fw_data_p) { int len; - const char *p = fw->data; - while (isspace(*p) && fw->size) { + size_t fw_size = *fw_size_p; + const char *p = *fw_data_p; + + while (isspace(*p) && fw_size) { p++; - fw->size--; + fw_size--; } - if (!fw->size) + if (!fw_size) return 0; - for (len = 0; len < fw->size; len++) { + for (len = 0; len < fw_size; len++) { if (!*p) break; if (*p == '\n') { @@ -770,8 +772,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw) *buf++ = *p++; } *buf = 0; - fw->size -= len; - fw->data = p; + *fw_size_p = fw_size - len; + *fw_data_p = p; remove_trail_spaces(buf); return 1; } @@ -779,29 +781,15 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw) /* * load a "patch" firmware file and parse it */ -int snd_hda_load_patch(struct hda_bus *bus, const char *patch) +int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf) { - int err; - const struct firmware *fw; - struct firmware tmp; char buf[128]; struct hda_codec *codec; int line_mode; - struct device *dev = bus->card->dev; - - if (snd_BUG_ON(!dev)) - return -ENODEV; - err = request_firmware(&fw, patch, dev); - if (err < 0) { - printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n", - patch); - return err; - } - tmp = *fw; line_mode = LINE_MODE_NONE; codec = NULL; - while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) { + while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) { if (!*buf || *buf == '#' || *buf == '\n') continue; if (*buf == '[') @@ -810,7 +798,6 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch) (codec || !patch_items[line_mode].need_codec)) patch_items[line_mode].parser(buf, bus, &codec); } - release_firmware(fw); return 0; } EXPORT_SYMBOL_HDA(snd_hda_load_patch); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 60882c6..209bea4 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -55,6 +55,7 @@ #include <sound/initval.h> #include <linux/vgaarb.h> #include <linux/vga_switcheroo.h> +#include <linux/firmware.h> #include "hda_codec.h" @@ -109,8 +110,15 @@ MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " #endif #ifdef CONFIG_SND_HDA_POWER_SAVE +static int param_set_xint(const char *val, const struct kernel_param *kp); +static struct kernel_param_ops param_ops_xint = { + .set = param_set_xint, + .get = param_get_int, +}; +#define param_check_xint param_check_int + static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; -module_param(power_save, int, 0644); +module_param(power_save, xint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); @@ -471,6 +479,10 @@ struct azx { struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; +#ifdef CONFIG_SND_HDA_PATCH_LOADER + const struct firmware *fw; +#endif + /* flags */ int position_fix[2]; /* for both playback/capture streams */ int poll_count; @@ -498,6 +510,9 @@ struct azx { /* reboot notifier (for mysterious hangup problem at power-down) */ struct notifier_block reboot_notifier; + + /* card list (for power_save trigger) */ + struct list_head list; }; /* driver types */ @@ -560,13 +575,17 @@ enum { * VGA-switcher support */ #ifdef SUPPORT_VGA_SWITCHEROO +#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) +#else +#define use_vga_switcheroo(chip) 0 +#endif + +#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER) #define DELAYED_INIT_MARK #define DELAYED_INITDATA_MARK -#define use_vga_switcheroo(chip) ((chip)->use_vga_switcheroo) #else #define DELAYED_INIT_MARK __devinit #define DELAYED_INITDATA_MARK __devinitdata -#define use_vga_switcheroo(chip) 0 #endif static char *driver_short_names[] DELAYED_INITDATA_MARK = { @@ -2399,13 +2418,54 @@ static void azx_power_notify(struct hda_bus *bus) !bus->power_keep_link_on) azx_stop_chip(chip); } + +static DEFINE_MUTEX(card_list_lock); +static LIST_HEAD(card_list); + +static void azx_add_card_list(struct azx *chip) +{ + mutex_lock(&card_list_lock); + list_add(&chip->list, &card_list); + mutex_unlock(&card_list_lock); +} + +static void azx_del_card_list(struct azx *chip) +{ + mutex_lock(&card_list_lock); + list_del_init(&chip->list); + mutex_unlock(&card_list_lock); +} + +/* trigger power-save check at writing parameter */ +static int param_set_xint(const char *val, const struct kernel_param *kp) +{ + struct azx *chip; + struct hda_codec *c; + int prev = power_save; + int ret = param_set_int(val, kp); + + if (ret || prev == power_save) + return ret; + + mutex_lock(&card_list_lock); + list_for_each_entry(chip, &card_list, list) { + if (!chip->bus || chip->disabled) + continue; + list_for_each_entry(c, &chip->bus->codec_list, list) + snd_hda_power_sync(c); + } + mutex_unlock(&card_list_lock); + return 0; +} +#else +#define azx_add_card_list(chip) /* NOP */ +#define azx_del_card_list(chip) /* NOP */ #endif /* CONFIG_SND_HDA_POWER_SAVE */ -#ifdef CONFIG_PM +#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) /* * power management */ - static int azx_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); @@ -2463,10 +2523,8 @@ static int azx_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume); #define AZX_PM_OPS &azx_pm #else -#define azx_suspend(dev) -#define azx_resume(dev) #define AZX_PM_OPS NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */ /* @@ -2599,6 +2657,8 @@ static int azx_free(struct azx *chip) { int i; + azx_del_card_list(chip); + azx_notifier_unregister(chip); if (use_vga_switcheroo(chip)) { @@ -2640,6 +2700,10 @@ static int azx_free(struct azx *chip) pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip->azx_dev); +#ifdef CONFIG_SND_HDA_PATCH_LOADER + if (chip->fw) + release_firmware(chip->fw); +#endif kfree(chip); return 0; @@ -2902,6 +2966,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->dev_index = dev; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&chip->pcm_list); + INIT_LIST_HEAD(&chip->list); init_vga_switcheroo(chip); chip->position_fix[0] = chip->position_fix[1] = @@ -3147,12 +3212,40 @@ static void power_down_all_codecs(struct azx *chip) #endif } +#ifdef CONFIG_SND_HDA_PATCH_LOADER +/* callback from request_firmware_nowait() */ +static void azx_firmware_cb(const struct firmware *fw, void *context) +{ + struct snd_card *card = context; + struct azx *chip = card->private_data; + struct pci_dev *pci = chip->pci; + + if (!fw) { + snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n"); + goto error; + } + + chip->fw = fw; + if (!chip->disabled) { + /* continue probing */ + if (azx_probe_continue(chip)) + goto error; + } + return; /* OK */ + + error: + snd_card_free(card); + pci_set_drvdata(pci, NULL); +} +#endif + static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; struct azx *chip; + bool probe_now; int err; if (dev >= SNDRV_CARDS) @@ -3168,15 +3261,28 @@ static int __devinit azx_probe(struct pci_dev *pci, return err; } - /* set this here since it's referred in snd_hda_load_patch() */ snd_card_set_dev(card, &pci->dev); err = azx_create(card, pci, dev, pci_id->driver_data, &chip); if (err < 0) goto out_free; card->private_data = chip; + probe_now = !chip->disabled; - if (!chip->disabled) { +#ifdef CONFIG_SND_HDA_PATCH_LOADER + if (patch[dev] && *patch[dev]) { + snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", + patch[dev]); + err = request_firmware_nowait(THIS_MODULE, true, patch[dev], + &pci->dev, GFP_KERNEL, card, + azx_firmware_cb); + if (err < 0) + goto out_free; + probe_now = false; /* continued in azx_firmware_cb() */ + } +#endif /* CONFIG_SND_HDA_PATCH_LOADER */ + + if (probe_now) { err = azx_probe_continue(chip); if (err < 0) goto out_free; @@ -3206,12 +3312,13 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) if (err < 0) goto out_free; #ifdef CONFIG_SND_HDA_PATCH_LOADER - if (patch[dev] && *patch[dev]) { - snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", - patch[dev]); - err = snd_hda_load_patch(chip->bus, patch[dev]); + if (chip->fw) { + err = snd_hda_load_patch(chip->bus, chip->fw->size, + chip->fw->data); if (err < 0) goto out_free; + release_firmware(chip->fw); /* no longer needed */ + chip->fw = NULL; } #endif if ((probe_only[dev] & 1) == 0) { @@ -3237,6 +3344,7 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) chip->running = 1; power_down_all_codecs(chip); azx_notifier_register(chip); + azx_add_card_list(chip); return 0; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 6894ec6..045e5d3 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -402,6 +402,9 @@ static void print_digital_conv(struct snd_info_buffer *buffer, { unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); + unsigned char digi2 = digi1 >> 8; + unsigned char digi3 = digi1 >> 16; + snd_iprintf(buffer, " Digital:"); if (digi1 & AC_DIG1_ENABLE) snd_iprintf(buffer, " Enabled"); @@ -419,9 +422,13 @@ static void print_digital_conv(struct snd_info_buffer *buffer, snd_iprintf(buffer, " Pro"); if (digi1 & AC_DIG1_LEVEL) snd_iprintf(buffer, " GenLevel"); + if (digi3 & AC_DIG3_KAE) + snd_iprintf(buffer, " KAE"); snd_iprintf(buffer, "\n"); snd_iprintf(buffer, " Digital category: 0x%x\n", - (digi1 >> 8) & AC_DIG2_CC); + digi2 & AC_DIG2_CC); + snd_iprintf(buffer, " IEC Coding Type: 0x%x\n", + digi3 & AC_DIG3_ICT); } static const char *get_pwr_state(u32 state) diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h index 9884871..d42fe91 100644 --- a/sound/pci/hda/hda_trace.h +++ b/sound/pci/hda/hda_trace.h @@ -58,6 +58,7 @@ TRACE_EVENT(hda_bus_reset, TP_printk("[%d]", __entry->card) ); +#ifdef CONFIG_SND_HDA_POWER_SAVE DECLARE_EVENT_CLASS(hda_power, TP_PROTO(struct hda_codec *codec), @@ -87,6 +88,31 @@ DEFINE_EVENT(hda_power, hda_power_up, TP_ARGS(codec) ); +TRACE_EVENT(hda_power_count, + TP_PROTO(struct hda_codec *codec), + TP_ARGS(codec), + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, addr ) + __field( int, power_count ) + __field( int, power_on ) + __field( int, power_transition ) + ), + + TP_fast_assign( + __entry->card = (codec)->bus->card->number; + __entry->addr = (codec)->addr; + __entry->power_count = (codec)->power_count; + __entry->power_on = (codec)->power_on; + __entry->power_transition = (codec)->power_transition; + ), + + TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d", + __entry->card, __entry->addr, __entry->power_count, + __entry->power_on, __entry->power_transition) +); +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + TRACE_EVENT(hda_unsol_event, TP_PROTO(struct hda_bus *bus, u32 res, u32 res_ex), diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0208fa1..2121885 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -4814,6 +4814,32 @@ static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { { } /* end */ }; +/* simple auto-mute control for AD1882 3-stack board */ +#define AD1882_HP_EVENT 0x01 + +static void ad1882_3stack_automute(struct hda_codec *codec) +{ + bool mute = snd_hda_jack_detect(codec, 0x11); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + mute ? 0 : PIN_OUT); +} + +static int ad1882_3stack_automute_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1882_3stack_automute(codec); + return 0; +} + +static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) +{ + switch (res >> 26) { + case AD1882_HP_EVENT: + ad1882_3stack_automute(codec); + break; + } +} + static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), @@ -4928,6 +4954,11 @@ static const struct hda_verb ad1882_init_verbs[] = { { } /* end */ }; +static const struct hda_verb ad1882_3stack_automute_verbs[] = { + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, + { } /* end */ +}; + #ifdef CONFIG_SND_HDA_POWER_SAVE static const struct hda_amp_list ad1882_loopbacks[] = { { 0x20, HDA_INPUT, 0 }, /* Front Mic */ @@ -4942,12 +4973,14 @@ static const struct hda_amp_list ad1882_loopbacks[] = { enum { AD1882_3STACK, AD1882_6STACK, + AD1882_3STACK_AUTOMUTE, AD1882_MODELS }; static const char * const ad1882_models[AD1986A_MODELS] = { [AD1882_3STACK] = "3stack", [AD1882_6STACK] = "6stack", + [AD1882_3STACK_AUTOMUTE] = "3stack-automute", }; @@ -5002,6 +5035,7 @@ static int patch_ad1882(struct hda_codec *codec) switch (board_config) { default: case AD1882_3STACK: + case AD1882_3STACK_AUTOMUTE: spec->num_mixers = 3; spec->mixers[2] = ad1882_3stack_mixers; spec->channel_mode = ad1882_modes; @@ -5009,6 +5043,12 @@ static int patch_ad1882(struct hda_codec *codec) spec->need_dac_fix = 1; spec->multiout.max_channels = 2; spec->multiout.num_dacs = 1; + if (board_config != AD1882_3STACK) { + spec->init_verbs[spec->num_init_verbs++] = + ad1882_3stack_automute_verbs; + codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; + codec->patch_ops.init = ad1882_3stack_automute_init; + } break; case AD1882_6STACK: spec->num_mixers = 3; |