diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 69 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 3 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 250 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 1240 |
6 files changed, 926 insertions, 645 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d7d9446..fb07def 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid); +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len); + /** * snd_hda_get_connections - get connection list * @codec: the HDA codec @@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); * Returns the number of connections, or a negative error code. */ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) + hda_nid_t *conn_list, int max_conns) +{ + struct snd_array *array = &codec->conn_lists; + int i, len, old_used; + hda_nid_t list[HDA_MAX_CONNECTIONS]; + + /* look up the cached results */ + for (i = 0; i < array->used; ) { + hda_nid_t *p = snd_array_elem(array, i); + len = p[1]; + if (nid == *p) + return copy_conn_list(nid, conn_list, max_conns, + p + 2, len); + i += len + 2; + } + + len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); + if (len < 0) + return len; + + /* add to the cache */ + old_used = array->used; + if (!add_conn_list(array, nid) || !add_conn_list(array, len)) + goto error_add; + for (i = 0; i < len; i++) + if (!add_conn_list(array, list[i])) + goto error_add; + + return copy_conn_list(nid, conn_list, max_conns, list, len); + + error_add: + array->used = old_used; + return -ENOMEM; +} +EXPORT_SYMBOL_HDA(snd_hda_get_connections); + +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) { unsigned int parm; int i, conn_len, conns; @@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } -EXPORT_SYMBOL_HDA(snd_hda_get_connections); +static bool add_conn_list(struct snd_array *array, hda_nid_t nid) +{ + hda_nid_t *p = snd_array_new(array); + if (!p) + return false; + *p = nid; + return true; +} + +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst, + hda_nid_t *src, int len) +{ + if (len > max_dst) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + len, nid); + return -EINVAL; + } + memcpy(dst, src, len * sizeof(hda_nid_t)); + return len; +} /** * snd_hda_queue_unsol_event - add an unsolicited event to queue @@ -1019,6 +1082,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) list_del(&codec->list); snd_array_free(&codec->mixers); snd_array_free(&codec->nids); + snd_array_free(&codec->conn_lists); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1079,6 +1143,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); + snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e46d542..7d57a66 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -825,6 +825,8 @@ struct hda_codec { struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ + struct snd_array conn_lists; /* connection-list array */ + struct mutex spdif_mutex; struct mutex control_mutex; unsigned int spdif_status; /* IEC958 status bits */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 70a9d32..6f891ee 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH10}," "{Intel, PCH}," "{Intel, CPT}," + "{Intel, PPT}," "{Intel, PBG}," "{Intel, SCH}," "{ATI, SB450}," @@ -2759,6 +2760,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH }, + /* Panther Point */ + { PCI_DEVICE(0x8086, 0x1e20), .driver_data = AZX_DRIVER_PCH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, /* Generic Intel */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 30c4409..e631874 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -375,6 +375,7 @@ struct alc_spec { #ifdef CONFIG_SND_HDA_POWER_SAVE void (*power_hook)(struct hda_codec *codec); #endif + void (*shutup)(struct hda_codec *codec); /* for pin sensing */ unsigned int sense_updated: 1; @@ -1236,6 +1237,43 @@ static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on) on ? 2 : 0); } +/* turn on/off EAPD controls of the codec */ +static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) +{ + /* We currently only handle front, HP */ + switch (codec->vendor_id) { + case 0x10ec0260: + set_eapd(codec, 0x0f, on); + set_eapd(codec, 0x10, on); + break; + case 0x10ec0262: + case 0x10ec0267: + case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0270: + case 0x10ec0272: + case 0x10ec0660: + case 0x10ec0662: + case 0x10ec0663: + case 0x10ec0665: + case 0x10ec0862: + case 0x10ec0889: + case 0x10ec0892: + set_eapd(codec, 0x14, on); + set_eapd(codec, 0x15, on); + break; + } +} + +/* generic shutup callback; + * just turning off EPAD and a little pause for avoiding pop-noise + */ +static void alc_eapd_shutup(struct hda_codec *codec) +{ + alc_auto_setup_eapd(codec, false); + msleep(200); +} + static void alc_auto_init_amp(struct hda_codec *codec, int type) { unsigned int tmp; @@ -1251,27 +1289,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; case ALC_INIT_DEFAULT: - switch (codec->vendor_id) { - case 0x10ec0260: - set_eapd(codec, 0x0f, 1); - set_eapd(codec, 0x10, 1); - break; - case 0x10ec0262: - case 0x10ec0267: - case 0x10ec0268: - case 0x10ec0269: - case 0x10ec0270: - case 0x10ec0272: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0862: - case 0x10ec0889: - set_eapd(codec, 0x14, 1); - set_eapd(codec, 0x15, 1); - break; - } + alc_auto_setup_eapd(codec, true); switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x1a, 0, @@ -4193,6 +4211,10 @@ static int alc_build_pcms(struct hda_codec *codec) static inline void alc_shutup(struct hda_codec *codec) { + struct alc_spec *spec = codec->spec; + + if (spec && spec->shutup) + spec->shutup(codec); snd_hda_shutup_pins(codec); } @@ -4226,28 +4248,7 @@ static void alc_free(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE static void alc_power_eapd(struct hda_codec *codec) { - /* We currently only handle front, HP */ - switch (codec->vendor_id) { - case 0x10ec0260: - set_eapd(codec, 0x0f, 0); - set_eapd(codec, 0x10, 0); - break; - case 0x10ec0262: - case 0x10ec0267: - case 0x10ec0268: - case 0x10ec0269: - case 0x10ec0270: - case 0x10ec0272: - case 0x10ec0660: - case 0x10ec0662: - case 0x10ec0663: - case 0x10ec0665: - case 0x10ec0862: - case 0x10ec0889: - set_eapd(codec, 0x14, 0); - set_eapd(codec, 0x15, 0); - break; - } + alc_auto_setup_eapd(codec, false); } static int alc_suspend(struct hda_codec *codec, pm_message_t state) @@ -4263,6 +4264,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) #ifdef SND_HDA_NEEDS_RESUME static int alc_resume(struct hda_codec *codec) { + msleep(150); /* to avoid pop noise */ codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); @@ -7383,6 +7385,7 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) spec->init_hook = alc260_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; @@ -10849,6 +10852,11 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) const struct hda_input_mux *imux; int conns, mute, idx, item; + /* mute ADC */ + snd_hda_codec_write(codec, spec->adc_nids[c], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + conns = snd_hda_get_connections(codec, nid, conn_list, ARRAY_SIZE(conn_list)); if (conns < 0) @@ -13018,6 +13026,7 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) spec->init_hook = alc262_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -14092,6 +14101,7 @@ static int patch_alc268(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); @@ -14803,7 +14813,6 @@ static void alc269_auto_init(struct hda_codec *codec) alc_inithook(codec); } -#ifdef SND_HDA_NEEDS_RESUME static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) { int val = alc_read_coef_idx(codec, 0x04); @@ -14814,25 +14823,17 @@ static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) alc_write_coef_idx(codec, 0x04, val); } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static int alc269_suspend(struct hda_codec *codec, pm_message_t state) +static void alc269_shutup(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) alc269_toggle_power_output(codec, 0); if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { alc269_toggle_power_output(codec, 0); msleep(150); } - - alc_shutup(codec); - if (spec && spec->power_hook) - spec->power_hook(codec); - return 0; } -#endif /* CONFIG_SND_HDA_POWER_SAVE */ +#ifdef SND_HDA_NEEDS_RESUME static int alc269_resume(struct hda_codec *codec) { if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { @@ -15320,14 +15321,12 @@ static int patch_alc269(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; -#ifdef CONFIG_SND_HDA_POWER_SAVE - codec->patch_ops.suspend = alc269_suspend; -#endif #ifdef SND_HDA_NEEDS_RESUME codec->patch_ops.resume = alc269_resume; #endif if (board_config == ALC269_AUTO) spec->init_hook = alc269_auto_init; + spec->shutup = alc269_shutup; alc_init_jacks(codec); #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -17433,6 +17432,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (board_config == ALC861VD_AUTO) spec->init_hook = alc861vd_auto_init; + spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; @@ -17455,8 +17455,8 @@ static int patch_alc861vd(struct hda_codec *codec) #define ALC662_DIGOUT_NID 0x06 #define ALC662_DIGIN_NID 0x0a -static hda_nid_t alc662_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ +static hda_nid_t alc662_dac_nids[3] = { + /* front, rear, clfe */ 0x02, 0x03, 0x04 }; @@ -17945,32 +17945,13 @@ static struct hda_verb alc662_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* always trun on EAPD */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, - { } }; -static struct hda_verb alc663_init_verbs[] = { - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } -}; - -static struct hda_verb alc272_init_verbs[] = { - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +static struct hda_verb alc662_eapd_init_verbs[] = { + /* always trun on EAPD */ + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, { } }; @@ -18714,7 +18695,7 @@ static const char * const alc662_models[ALC662_MODEL_LAST] = { [ALC662_3ST_2ch_DIG] = "3stack-dig", [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC662_3ST_6ch] = "3stack-6ch", - [ALC662_5ST_DIG] = "6stack-dig", + [ALC662_5ST_DIG] = "5stack-dig", [ALC662_LENOVO_101E] = "lenovo-101e", [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", @@ -18820,7 +18801,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { static struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { .mixers = { alc662_3ST_2ch_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18831,7 +18812,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_3ST_6ch_DIG] = { .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18843,7 +18824,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_3ST_6ch] = { .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), @@ -18853,7 +18834,7 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_5ST_DIG] = { .mixers = { alc662_base_mixer, alc662_chmode_mixer }, - .init_verbs = { alc662_init_verbs }, + .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18864,7 +18845,9 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC662_LENOVO_101E] = { .mixers = { alc662_lenovo_101e_mixer }, - .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), @@ -18876,6 +18859,7 @@ static struct alc_config_preset alc662_presets[] = { [ALC662_ASUS_EEEPC_P701] = { .mixers = { alc662_eeepc_p701_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_eeepc_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -18889,6 +18873,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc662_eeepc_ep20_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_eeepc_ep20_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -18902,6 +18887,7 @@ static struct alc_config_preset alc662_presets[] = { [ALC662_ECS] = { .mixers = { alc662_ecs_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_ecs_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -18913,7 +18899,9 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC663_ASUS_M51VA] = { .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18925,7 +18913,9 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC663_ASUS_G71V] = { .mixers = { alc663_g71v_mixer }, - .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g71v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18937,7 +18927,9 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC663_ASUS_H13] = { .mixers = { alc663_m51va_mixer }, - .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), @@ -18947,7 +18939,9 @@ static struct alc_config_preset alc662_presets[] = { }, [ALC663_ASUS_G50V] = { .mixers = { alc663_g50v_mixer }, - .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc663_g50v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, .dig_out_nid = ALC662_DIGOUT_NID, @@ -18962,6 +18956,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -18977,6 +18972,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc662_1bjd_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc662_1bjd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -18991,6 +18987,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_two_hp_m1_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_two_hp_amic_m1_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19006,6 +19003,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_asus_21jd_clfe_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs}, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19021,6 +19019,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_asus_15jd_clfe_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_15jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19036,6 +19035,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_two_hp_m2_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_two_hp_amic_m2_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19051,6 +19051,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_mode7_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_mode7_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19066,6 +19067,7 @@ static struct alc_config_preset alc662_presets[] = { .mixers = { alc663_mode8_mixer }, .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_mode8_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .hp_nid = 0x03, @@ -19080,9 +19082,11 @@ static struct alc_config_preset alc662_presets[] = { [ALC272_DELL] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc272_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc662_dac_nids, + .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc272_adc_nids, .num_adc_nids = ARRAY_SIZE(alc272_adc_nids), @@ -19095,9 +19099,11 @@ static struct alc_config_preset alc662_presets[] = { [ALC272_DELL_ZM1] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc662_auto_capture_mixer, - .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs }, + .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, + alc272_dell_zm1_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc662_dac_nids, + .dac_nids = alc272_dac_nids, .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), .adc_nids = alc662_adc_nids, .num_adc_nids = 1, @@ -19110,6 +19116,7 @@ static struct alc_config_preset alc662_presets[] = { [ALC272_SAMSUNG_NC10] = { .mixers = { alc272_nc10_mixer }, .init_verbs = { alc662_init_verbs, + alc662_eapd_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc272_dac_nids), .dac_nids = alc272_dac_nids, @@ -19128,16 +19135,17 @@ static struct alc_config_preset alc662_presets[] = { */ /* convert from MIX nid to DAC */ -static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid) -{ - if (nid == 0x0f) - return 0x02; - else if (nid >= 0x0c && nid <= 0x0e) - return nid - 0x0c + 0x02; - else if (nid == 0x26) /* ALC887-VD has this DAC too */ - return 0x25; - else - return 0; +static hda_nid_t alc662_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) +{ + hda_nid_t list[4]; + int i, num; + + num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); + for (i = 0; i < num; i++) { + if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) + return list[i]; + } + return 0; } /* get MIX nid connected to the given pin targeted to DAC */ @@ -19149,7 +19157,7 @@ static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); for (i = 0; i < num; i++) { - if (alc662_mix_to_dac(mix[i]) == dac) + if (alc662_mix_to_dac(codec, mix[i]) == dac) return mix[i]; } return 0; @@ -19166,7 +19174,7 @@ static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin) if (num < 0) return 0; for (i = 0; i < num; i++) { - hda_nid_t nid = alc662_mix_to_dac(srcs[i]); + hda_nid_t nid = alc662_mix_to_dac(codec, srcs[i]); if (!nid) continue; for (j = 0; j < spec->multiout.num_dacs; j++) @@ -19315,14 +19323,21 @@ static void alc662_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t srcs[HDA_MAX_CONNECTIONS]; alc_set_pin_output(codec, nid, pin_type); - /* need the manual connection? */ num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - if (num <= 1) - return; for (i = 0; i < num; i++) { - if (alc662_mix_to_dac(srcs[i]) != dac) + if (alc662_mix_to_dac(codec, srcs[i]) != dac) continue; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); + /* need the manual connection? */ + if (num > 1) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, i); + /* unmute mixer widget inputs */ + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write(codec, srcs[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); return; } } @@ -19425,14 +19440,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - add_verb(spec, alc662_init_verbs); - if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || - codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) - add_verb(spec, alc663_init_verbs); - - if (codec->vendor_id == 0x10ec0272) - add_verb(spec, alc272_init_verbs); - err = alc_auto_add_mic_boost(codec); if (err < 0) return err; @@ -19634,6 +19641,7 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; + spec->shutup = alc_eapd_shutup; alc_init_jacks(codec); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a2f57e3..75b7155 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5449,6 +5449,13 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; spec->init = stac92hd83xxx_core_init; + if (codec->bus->pci && codec->bus->pci->vendor == PCI_VENDOR_ID_AMD) { + snd_printk(KERN_INFO "idt92hd83xxx: " + "Enable sync_write for AMD chipset\n"); + codec->bus->sync_write = 1; + codec->bus->allow_bus_reset = 1; + } + spec->board_config = snd_hda_check_board_config(codec, STAC_92HD83XXX_MODELS, stac92hd83xxx_models, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 1371b57..15b57a1 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -98,9 +98,15 @@ enum VIA_HDA_CODEC { VT1716S, VT2002P, VT1812, + VT1802, CODEC_TYPES, }; +#define VT2002P_COMPATIBLE(spec) \ + ((spec)->codec_type == VT2002P ||\ + (spec)->codec_type == VT1812 ||\ + (spec)->codec_type == VT1802) + struct via_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[6]; @@ -154,6 +160,9 @@ struct via_spec { struct delayed_work vt1708_hp_work; int vt1708_jack_detectect; int vt1708_hp_present; + + void (*set_widgets_power_state)(struct hda_codec *codec); + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -218,17 +227,19 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1812; else if (dev_id == 0x0440) codec_type = VT1708S; + else if ((dev_id & 0xfff) == 0x446) + codec_type = VT1802; else codec_type = UNKNOWN; return codec_type; }; +#define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 -#define VIA_JACK_EVENT 0x04 -#define VIA_MONO_EVENT 0x08 -#define VIA_SPEAKER_EVENT 0x10 -#define VIA_BIND_HP_EVENT 0x20 +#define VIA_MONO_EVENT 0x03 +#define VIA_SPEAKER_EVENT 0x04 +#define VIA_BIND_HP_EVENT 0x05 enum { VIA_CTL_WIDGET_VOL, @@ -245,7 +256,6 @@ enum { }; static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); -static void set_jack_power_state(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); static void vt1708_start_hp_work(struct via_spec *spec) @@ -271,6 +281,12 @@ static void vt1708_stop_hp_work(struct via_spec *spec) cancel_delayed_work_sync(&spec->vt1708_hp_work); } +static void set_widgets_power_state(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + if (spec->set_widgets_power_state) + spec->set_widgets_power_state(codec); +} static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -278,7 +294,7 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { if (is_aa_path_mute(codec)) @@ -602,482 +618,6 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -static void set_jack_power_state(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int imux_is_smixer; - unsigned int parm; - - if (spec->codec_type == VT1702) { - imux_is_smixer = snd_hda_codec_read( - codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 1/2/5 (14h/15h/18h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x14, &parm); - set_pin_power_state(codec, 0x15, &parm); - set_pin_power_state(codec, 0x18, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */ - /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW 3/4 (16h/17h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x16, &parm); - set_pin_power_state(codec, 0x17, &parm); - /* MW0 (1ah), AOW 0/1 (10h/1dh) */ - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, - parm); - } else if (spec->codec_type == VT1708B_8CH - || spec->codec_type == VT1708B_4CH - || spec->codec_type == VT1708S) { - /* SW0 (17h) = stereo mixer */ - int is_8ch = spec->codec_type != VT1708B_4CH; - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) - == ((spec->codec_type == VT1708S) ? 5 : 0); - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW 0/1 (13h/14h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW6 (22h), SW2 (26h), AOW2 (24h) */ - if (is_8ch) { - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x22, &parm); - if (spec->smart51_enabled) - parm = AC_PWRST_D0; - snd_hda_codec_write(codec, 0x26, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x24, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* PW 3/4/7 (1ch/1dh/23h) */ - parm = AC_PWRST_D3; - /* force to D0 for internal Speaker */ - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - if (is_8ch) - set_pin_power_state(codec, 0x23, &parm); - /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - if (is_8ch) { - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x27, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1718S) { - /* MUX6 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x27, &parm); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW2 (26h), AOW2 (ah) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW0/1 (24h/25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - set_pin_power_state(codec, 0x25, &parm); - if (!spec->hp_independent_mode) /* check for redirected HP */ - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, - parm); - /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ - snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - if (spec->hp_independent_mode) { - /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x1b, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0xc, 0, - AC_VERB_SET_POWER_STATE, parm); - } - } else if (spec->codec_type == VT1716S) { - unsigned int mono_out, present; - /* SW0 (17h) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 1/2/5 (1ah/1bh/1eh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1a, &parm); - set_pin_power_state(codec, 0x1b, &parm); - set_pin_power_state(codec, 0x1e, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* SW0 (17h), AIW0(13h) */ - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, - parm); - - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1e, &parm); - /* PW11 (22h) */ - if (spec->dmic_enabled) - set_pin_power_state(codec, 0x22, &parm); - else - snd_hda_codec_write( - codec, 0x22, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - - /* SW2(26h), AIW1(14h) */ - snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* outputs */ - /* PW0 (19h), SW1 (18h), AOW1 (11h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x19, &parm); - /* Smart 5.1 PW2(1bh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1b, &parm); - snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW7 (23h), SW3 (27h), AOW3 (25h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x23, &parm); - /* Smart 5.1 PW1(1ah) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1a, &parm); - snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) - set_pin_power_state(codec, 0x1e, &parm); - snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* Mono out */ - /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_jack_detect(codec, 0x1c); - if (present) - mono_out = 0; - else { - present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) - mono_out = 0; - else - mono_out = 1; - } - parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; - snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, - parm); - snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, - parm); - - /* PW 3/4 (1ch/1dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x1c, &parm); - set_pin_power_state(codec, 0x1d, &parm); - /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) - snd_hda_codec_write(codec, 0x25, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* force to D0 for internal Speaker */ - /* MW0 (16h), AOW0 (10h) */ - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, - imux_is_smixer ? AC_PWRST_D0 : parm); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, - mono_out ? AC_PWRST_D0 : parm); - } else if (spec->codec_type == VT2002P) { - unsigned int present; - /* MUX9 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (26h), MW4 (1ch), MUX4(37h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x26, &parm); - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x37, - 0, AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x19, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Class-D */ - /* PW0 (24h), MW0(18h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* Mono Out */ - /* PW15 (31h), MW8(17h), MUX8(3bh) */ - present = snd_hda_jack_detect(codec, 0x26); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else { - snd_hda_codec_write( - codec, 0x17, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - snd_hda_codec_write( - codec, 0x3b, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } else if (spec->codec_type == VT1812) { - unsigned int present; - /* MUX10 (1eh) = stereo mixer */ - imux_is_smixer = snd_hda_codec_read( - codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; - /* inputs */ - /* PW 5/6/7 (29h/2ah/2bh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x29, &parm); - set_pin_power_state(codec, 0x2a, &parm); - set_pin_power_state(codec, 0x2b, &parm); - if (imux_is_smixer) - parm = AC_PWRST_D0; - /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ - snd_hda_codec_write(codec, 0x1e, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x1f, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x10, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x11, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* outputs */ - /* AOW0 (8h)*/ - snd_hda_codec_write(codec, 0x8, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - - /* PW4 (28h), MW4 (18h), MUX4(38h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x28, &parm); - snd_hda_codec_write(codec, 0x18, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x38, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x25, &parm); - snd_hda_codec_write(codec, 0x15, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x35, 0, - AC_VERB_SET_POWER_STATE, parm); - if (spec->hp_independent_mode) { - snd_hda_codec_write(codec, 0x9, 0, - AC_VERB_SET_POWER_STATE, parm); - } - - /* Internal Speaker */ - /* PW0 (24h), MW0(14h), MUX0(34h) */ - present = snd_hda_jack_detect(codec, 0x25); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x24, &parm); - if (present) { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x14, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x34, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - /* Mono Out */ - /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ - present = snd_hda_jack_detect(codec, 0x28); - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x31, &parm); - if (present) { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - } else { - snd_hda_codec_write(codec, 0x1c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3c, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - snd_hda_codec_write(codec, 0x3e, 0, - AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - } - - /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ - parm = AC_PWRST_D3; - set_pin_power_state(codec, 0x33, &parm); - snd_hda_codec_write(codec, 0x1d, 0, - AC_VERB_SET_POWER_STATE, parm); - snd_hda_codec_write(codec, 0x3d, 0, - AC_VERB_SET_POWER_STATE, parm); - - /* MW9 (21h) */ - if (imux_is_smixer || !is_aa_path_mute(codec)) - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - else - snd_hda_codec_write( - codec, 0x21, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - } -} - /* * input MUX handling */ @@ -1120,7 +660,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return ret; } @@ -1168,6 +708,9 @@ static hda_nid_t side_mute_channel(struct via_spec *spec) case VT1709_10CH: return 0x29; case VT1708B_8CH: /* fall thru */ case VT1708S: return 0x27; + case VT2002P: return 0x19; + case VT1802: return 0x15; + case VT1812: return 0x15; default: return 0; } } @@ -1176,13 +719,22 @@ static int update_side_mute_status(struct hda_codec *codec) { /* mute side channel */ struct via_spec *spec = codec->spec; - unsigned int parm = spec->hp_independent_mode - ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; + unsigned int parm; hda_nid_t sw3 = side_mute_channel(spec); - if (sw3) - snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm); + if (sw3) { + if (VT2002P_COMPATIBLE(spec)) + parm = spec->hp_independent_mode ? + AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1); + else + parm = spec->hp_independent_mode ? + AMP_OUT_MUTE : AMP_OUT_UNMUTE; + snd_hda_codec_write(codec, sw3, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + if (spec->codec_type == VT1812) + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, parm); + } return 0; } @@ -1217,15 +769,14 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, || spec->codec_type == VT1702 || spec->codec_type == VT1718S || spec->codec_type == VT1716S - || spec->codec_type == VT2002P - || spec->codec_type == VT1812) { + || VT2002P_COMPATIBLE(spec)) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", spec->hp_independent_mode); } /* update jack power state */ - set_jack_power_state(codec); + set_widgets_power_state(codec); return 0; } @@ -1256,6 +807,7 @@ static int via_hp_build(struct hda_codec *codec) nid = 0x34; break; case VT2002P: + case VT1802: nid = 0x35; break; case VT1812: @@ -1443,7 +995,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, } } spec->smart51_enabled = *ucontrol->value.integer.value; - set_jack_power_state(codec); + set_widgets_power_state(codec); return 1; } @@ -1539,6 +1091,7 @@ static int is_aa_path_mute(struct hda_codec *codec) break; case VT2002P: case VT1812: + case VT1802: nid_mixer = 0x21; start_idx = 0; end_idx = 2; @@ -1603,6 +1156,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) break; case VT2002P: case VT1812: + case VT1802: verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; @@ -1646,6 +1200,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* power down jack detect function */ + {0x1, 0xf81, 0x1}, { } }; @@ -1967,7 +1523,7 @@ static int via_build_controls(struct hda_codec *codec) } /* init power states */ - set_jack_power_state(codec); + set_widgets_power_state(codec); analog_low_current_mode(codec, 1); via_free_kctls(codec); /* no longer needed */ @@ -2131,7 +1687,7 @@ static void via_speaker_automute(struct hda_codec *codec) unsigned int hp_present; struct via_spec *spec = codec->spec; - if (spec->codec_type != VT2002P && spec->codec_type != VT1812) + if (!VT2002P_COMPATIBLE(spec)) return; hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); @@ -2190,17 +1746,21 @@ static void via_unsol_event(struct hda_codec *codec, unsigned int res) { res >>= 26; - if (res & VIA_HP_EVENT) + + if (res & VIA_JACK_EVENT) + set_widgets_power_state(codec); + + res &= ~VIA_JACK_EVENT; + + if (res == VIA_HP_EVENT) via_hp_automute(codec); - if (res & VIA_GPIO_EVENT) + else if (res == VIA_GPIO_EVENT) via_gpio_control(codec); - if (res & VIA_JACK_EVENT) - set_jack_power_state(codec); - if (res & VIA_MONO_EVENT) + else if (res == VIA_MONO_EVENT) via_mono_automute(codec); - if (res & VIA_SPEAKER_EVENT) + else if (res == VIA_SPEAKER_EVENT) via_speaker_automute(codec); - if (res & VIA_BIND_HP_EVENT) + else if (res == VIA_BIND_HP_EVENT) via_hp_bind_automute(codec); } @@ -2619,7 +2179,8 @@ static int via_auto_init(struct hda_codec *codec) via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_analog_input(codec); - if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { + + if (VT2002P_COMPATIBLE(spec)) { via_hp_bind_automute(codec); } else { via_hp_automute(codec); @@ -3642,6 +3203,87 @@ static struct hda_amp_list vt1708B_loopbacks[] = { { } /* end */ }; #endif + +static void set_widgets_power_state_vt1708B(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + int is_8ch = 0; + if ((spec->codec_type != VT1708B_4CH) && + (codec->vendor_id != 0x11064397)) + is_8ch = 1; + + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = + (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) + == ((spec->codec_type == VT1708S) ? 5 : 0)); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW 0/1 (13h/14h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW6 (22h), SW2 (26h), AOW2 (24h) */ + if (is_8ch) { + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x22, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x24, 0, + AC_VERB_SET_POWER_STATE, parm); + } else if (codec->vendor_id == 0x11064397) { + /* PW7(23h), SW2(27h), AOW2(25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + /* PW 3/4/7 (1ch/1dh/23h) */ + parm = AC_PWRST_D3; + /* force to D0 for internal Speaker */ + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + if (is_8ch) + set_pin_power_state(codec, 0x23, &parm); + + /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + if (is_8ch) { + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); +} + static int patch_vt1708S(struct hda_codec *codec); static int patch_vt1708B_8ch(struct hda_codec *codec) { @@ -3692,6 +3334,8 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) spec->loopback.amplist = vt1708B_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; } @@ -3742,6 +3386,8 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) spec->loopback.amplist = vt1708B_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; + return 0; } @@ -3810,6 +3456,18 @@ static struct hda_verb vt1708S_uniwill_init_verbs[] = { { } }; +static struct hda_verb vt1705_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + static struct hda_pcm_stream vt1708S_pcm_analog_playback = { .substreams = 2, .channels_min = 2, @@ -3823,6 +3481,19 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = { }, }; +static struct hda_pcm_stream vt1705_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close + }, +}; + static struct hda_pcm_stream vt1708S_pcm_analog_capture = { .substreams = 2, .channels_min = 2, @@ -3869,7 +3540,10 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.dac_nids[i] = 0x10; break; case AUTO_SEQ_CENLFE: - spec->multiout.dac_nids[i] = 0x24; + if (spec->codec->vendor_id == 0x11064397) + spec->multiout.dac_nids[i] = 0x25; + else + spec->multiout.dac_nids[i] = 0x24; break; case AUTO_SEQ_SURROUND: spec->multiout.dac_nids[i] = 0x11; @@ -3885,22 +3559,28 @@ static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, if (cfg->line_outs == 1) { spec->multiout.num_dacs = 3; spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11; - spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24; + if (spec->codec->vendor_id == 0x11064397) + spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x25; + else + spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24; } return 0; } /* add playback controls from the parsed DAC table */ -static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, +static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct via_spec *spec = codec->spec; char name[32]; static const char * const chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; - hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; + hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25}, + {0x10, 0x11, 0x25, 0} }; + hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27}, + {0x1C, 0x18, 0x27, 0} }; hda_nid_t nid, nid_vol, nid_mute; int i, err; @@ -3911,8 +3591,15 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, if (!nid && i > AUTO_SEQ_CENLFE) continue; - nid_vol = nid_vols[i]; - nid_mute = nid_mutes[i]; + if (codec->vendor_id == 0x11064397) { + nid_vol = nid_vols[1][i]; + nid_mute = nid_mutes[1][i]; + } else { + nid_vol = nid_vols[0][i]; + nid_mute = nid_mutes[0][i]; + } + if (!nid_vol && !nid_mute) + continue; if (i == AUTO_SEQ_CENLFE) { /* Center/LFE */ @@ -4066,7 +3753,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) return 0; /* can't find valid BIOS pin config */ - err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg); + err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); @@ -4133,17 +3820,29 @@ static int patch_vt1708S(struct hda_codec *codec) } spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; - spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; + if (codec->vendor_id == 0x11064397) + spec->init_verbs[spec->num_iverbs++] = + vt1705_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt1708S_uniwill_init_verbs; if (codec->vendor_id == 0x11060440) spec->stream_name_analog = "VT1818S Analog"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_analog = "VT1705 Analog"; else spec->stream_name_analog = "VT1708S Analog"; - spec->stream_analog_playback = &vt1708S_pcm_analog_playback; + if (codec->vendor_id == 0x11064397) + spec->stream_analog_playback = &vt1705_pcm_analog_playback; + else + spec->stream_analog_playback = &vt1708S_pcm_analog_playback; spec->stream_analog_capture = &vt1708S_pcm_analog_capture; if (codec->vendor_id == 0x11060440) spec->stream_name_digital = "VT1818S Digital"; + else if (codec->vendor_id == 0x11064397) + spec->stream_name_digital = "VT1705 Digital"; else spec->stream_name_digital = "VT1708S Digital"; spec->stream_digital_playback = &vt1708S_pcm_digital_playback; @@ -4181,6 +3880,15 @@ static int patch_vt1708S(struct hda_codec *codec) spec->stream_name_analog = "VT1818S Analog"; spec->stream_name_digital = "VT1818S Digital"; } + /* correct names for VT1705 */ + if (codec->vendor_id == 0x11064397) { + kfree(codec->chip_name); + codec->chip_name = kstrdup("VT1705", GFP_KERNEL); + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name); + } + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; return 0; } @@ -4438,6 +4146,37 @@ static struct hda_amp_list vt1702_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1702(struct hda_codec *codec) +{ + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + unsigned int parm; + /* inputs */ + /* PW 1/2/5 (14h/15h/18h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x14, &parm); + set_pin_power_state(codec, 0x15, &parm); + set_pin_power_state(codec, 0x18, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */ + /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW 3/4 (16h/17h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x17, &parm); + set_pin_power_state(codec, 0x16, &parm); + /* MW0 (1ah), AOW 0/1 (10h/1dh) */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); +} + static int patch_vt1702(struct hda_codec *codec) { struct via_spec *spec; @@ -4484,6 +4223,7 @@ static int patch_vt1702(struct hda_codec *codec) spec->loopback.amplist = vt1702_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1702; return 0; } @@ -4519,7 +4259,8 @@ static struct hda_verb vt1718S_volume_init_verbs[] = { {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - + /* Enable MW0 adjust Gain 5 */ + {0x1, 0xfb2, 0x10}, /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ @@ -4528,7 +4269,7 @@ static struct hda_verb vt1718S_volume_init_verbs[] = { {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, /* Setup default input of Front HP to MW9 */ {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, @@ -4825,6 +4566,72 @@ static struct hda_amp_list vt1718S_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1718S(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + /* MUX6 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x27, &parm); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW2 (26h), AOW2 (ah) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x2b, &parm); + snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW0 (24h), AOW0 (8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (!spec->hp_independent_mode) /* check for redirected HP */ + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ + snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + + /* PW1 (25h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x2a, &parm); + snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm); + + if (spec->hp_independent_mode) { + /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xc, 0, + AC_VERB_SET_POWER_STATE, parm); + } +} + static int patch_vt1718S(struct hda_codec *codec) { struct via_spec *spec; @@ -4886,6 +4693,8 @@ static int patch_vt1718S(struct hda_codec *codec) spec->loopback.amplist = vt1718S_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1718S; + return 0; } @@ -4925,8 +4734,7 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol, snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_CONNECT_SEL, index); spec->dmic_enabled = index; - set_jack_power_state(codec); - + set_widgets_power_state(codec); return 1; } @@ -5285,6 +5093,99 @@ static struct hda_amp_list vt1716S_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1716S(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + unsigned int mono_out, present; + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = + (snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_CONNECT_SEL, 0x00) == 5); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW0(13h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1e, &parm); + /* PW11 (22h) */ + if (spec->dmic_enabled) + set_pin_power_state(codec, 0x22, &parm); + else + snd_hda_codec_write(codec, 0x22, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + /* SW2(26h), AIW1(14h) */ + snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + /* Smart 5.1 PW2(1bh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW7 (23h), SW3 (27h), AOW3 (25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + /* Smart 5.1 PW1(1ah) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Smart 5.1 PW5(1eh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1e, &parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono out */ + /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ + present = snd_hda_jack_detect(codec, 0x1c); + + if (present) + mono_out = 0; + else { + present = snd_hda_jack_detect(codec, 0x1d); + if (!spec->hp_independent_mode && present) + mono_out = 0; + else + mono_out = 1; + } + parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW 3/4 (1ch/1dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + /* HP Independent Mode, power on AOW3 */ + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* force to D0 for internal Speaker */ + /* MW0 (16h), AOW0 (10h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); +} + static int patch_vt1716S(struct hda_codec *codec) { struct via_spec *spec; @@ -5339,6 +5240,7 @@ static int patch_vt1716S(struct hda_codec *codec) spec->loopback.amplist = vt1716S_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1716S; return 0; } @@ -5369,6 +5271,10 @@ static struct snd_kcontrol_new vt2002P_capture_mixer[] = { }; static struct hda_verb vt2002P_volume_init_verbs[] = { + /* Class-D speaker related verbs */ + {0x1, 0xfe0, 0x4}, + {0x1, 0xfe9, 0x80}, + {0x1, 0xfe2, 0x22}, /* * Unmute ADC0-1 and set the default input to mic-in */ @@ -5419,6 +5325,57 @@ static struct hda_verb vt2002P_volume_init_verbs[] = { {0x1, 0xfb8, 0x88}, { } }; +static struct hda_verb vt1802_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; static struct hda_verb vt2002P_uniwill_init_verbs[] = { @@ -5431,6 +5388,16 @@ static struct hda_verb vt2002P_uniwill_init_verbs[] = { {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, { } }; +static struct hda_verb vt1802_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; static struct hda_pcm_stream vt2002P_pcm_analog_playback = { .substreams = 2, @@ -5487,10 +5454,15 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { int err; + hda_nid_t sw_nid; if (!cfg->line_out_pins[0]) return -1; + if (spec->codec_type == VT1802) + sw_nid = 0x28; + else + sw_nid = 0x26; /* Line-Out: PortE */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, @@ -5500,7 +5472,7 @@ static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, return err; err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT)); + HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -5609,6 +5581,116 @@ static struct hda_amp_list vt2002P_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt2002P(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + unsigned int present; + /* MUX9 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + parm = AC_PWRST_D0; + /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm); + + if (spec->codec_type == VT1802) { + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW4 (26h), MW4 (1ch), MUX4(37h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x37, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + if (spec->codec_type == VT1802) { + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Class-D */ + /* PW0 (24h), MW0(18h/14h), MUX0(34h) */ + present = snd_hda_jack_detect(codec, 0x25); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + parm = present ? AC_PWRST_D3 : AC_PWRST_D0; + if (spec->codec_type == VT1802) + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, parm); + else + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm); + + /* Mono Out */ + present = snd_hda_jack_detect(codec, 0x26); + + parm = present ? AC_PWRST_D3 : AC_PWRST_D0; + if (spec->codec_type == VT1802) { + /* PW15 (33h), MW8(1ch), MUX8(3ch) */ + snd_hda_codec_write(codec, 0x33, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, parm); + } else { + /* PW15 (31h), MW8(17h), MUX8(3bh) */ + snd_hda_codec_write(codec, 0x31, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x17, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3b, 0, + AC_VERB_SET_POWER_STATE, parm); + } + /* MW9 (21h) */ + if (imux_is_smixer || !is_aa_path_mute(codec)) + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + else + snd_hda_codec_write(codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); +} /* patch for vt2002P */ static int patch_vt2002P(struct hda_codec *codec) @@ -5631,14 +5713,31 @@ static int patch_vt2002P(struct hda_codec *codec) "from BIOS. Using genenic mode...\n"); } - spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs; - spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs; + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_volume_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_volume_init_verbs; + + if (spec->codec_type == VT1802) + spec->init_verbs[spec->num_iverbs++] = + vt1802_uniwill_init_verbs; + else + spec->init_verbs[spec->num_iverbs++] = + vt2002P_uniwill_init_verbs; - spec->stream_name_analog = "VT2002P Analog"; + if (spec->codec_type == VT1802) + spec->stream_name_analog = "VT1802 Analog"; + else + spec->stream_name_analog = "VT2002P Analog"; spec->stream_analog_playback = &vt2002P_pcm_analog_playback; spec->stream_analog_capture = &vt2002P_pcm_analog_capture; - spec->stream_name_digital = "VT2002P Digital"; + if (spec->codec_type == VT1802) + spec->stream_name_digital = "VT1802 Digital"; + else + spec->stream_name_digital = "VT2002P Digital"; spec->stream_digital_playback = &vt2002P_pcm_digital_playback; if (!spec->adc_nids && spec->input_mux) { @@ -5660,6 +5759,7 @@ static int patch_vt2002P(struct hda_codec *codec) spec->loopback.amplist = vt2002P_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt2002P; return 0; } @@ -5931,6 +6031,97 @@ static struct hda_amp_list vt1812_loopbacks[] = { }; #endif +static void set_widgets_power_state_vt1812(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer = + snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + unsigned int parm; + unsigned int present; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + parm = AC_PWRST_D0; + /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm); + if (spec->hp_independent_mode) + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* Internal Speaker */ + /* PW0 (24h), MW0(14h), MUX0(34h) */ + present = snd_hda_jack_detect(codec, 0x25); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (present) { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + + /* Mono Out */ + /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ + present = snd_hda_jack_detect(codec, 0x28); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x31, &parm); + if (present) { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x33, &parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm); + +} /* patch for vt1812 */ static int patch_vt1812(struct hda_codec *codec) @@ -5984,6 +6175,7 @@ static int patch_vt1812(struct hda_codec *codec) spec->loopback.amplist = vt1812_loopbacks; #endif + spec->set_widgets_power_state = set_widgets_power_state_vt1812; return 0; } @@ -6035,7 +6227,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1708S}, { .id = 0x11063397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11064397, .name = "VT1708S", + { .id = 0x11064397, .name = "VT1705", .patch = patch_vt1708S}, { .id = 0x11065397, .name = "VT1708S", .patch = patch_vt1708S}, @@ -6076,6 +6268,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, { .id = 0x11060440, .name = "VT1818S", .patch = patch_vt1708S}, + { .id = 0x11060446, .name = "VT1802", + .patch = patch_vt2002P}, + { .id = 0x11068446, .name = "VT1802", + .patch = patch_vt2002P}, {} /* terminator */ }; |