ALSA: HDA: VIA Add support for codec VT1705CF.
Add support for new codec VT1705CF. When power on/off Audio output converter of VT1705CF, the stream tag will be cleared. But driver caches the value. So when power on Audio output converter, the update_conv_power_state() will restore the saved stream tag of it. Signed-off-by: Lydia Wang <lydiawang@viatech.com.cn> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
97768a8e65
commit
43737e0ae9
@ -76,6 +76,7 @@ enum VIA_HDA_CODEC {
|
||||
VT2002P,
|
||||
VT1812,
|
||||
VT1802,
|
||||
VT1705CF,
|
||||
CODEC_TYPES,
|
||||
};
|
||||
|
||||
@ -220,6 +221,7 @@ struct via_spec {
|
||||
int vt1708_hp_present;
|
||||
|
||||
void (*set_widgets_power_state)(struct hda_codec *codec);
|
||||
unsigned int dac_stream_tag[4];
|
||||
|
||||
struct hda_loopback_check loopback;
|
||||
int num_loopbacks;
|
||||
@ -296,6 +298,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
|
||||
codec_type = VT1708S;
|
||||
else if ((dev_id & 0xfff) == 0x446)
|
||||
codec_type = VT1802;
|
||||
else if (dev_id == 0x4760)
|
||||
codec_type = VT1705CF;
|
||||
else
|
||||
codec_type = UNKNOWN;
|
||||
return codec_type;
|
||||
@ -711,6 +715,28 @@ static void update_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 update_conv_power_state(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int parm, unsigned int index)
|
||||
{
|
||||
struct via_spec *spec = codec->spec;
|
||||
unsigned int format;
|
||||
if (snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_POWER_STATE, 0) == parm)
|
||||
return;
|
||||
format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
|
||||
if (format && (spec->dac_stream_tag[index] != format))
|
||||
spec->dac_stream_tag[index] = format;
|
||||
|
||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
|
||||
if (parm == AC_PWRST_D0) {
|
||||
format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
|
||||
if (!format && (spec->dac_stream_tag[index] != format))
|
||||
snd_hda_codec_write(codec, nid, 0,
|
||||
AC_VERB_SET_CHANNEL_STREAMID,
|
||||
spec->dac_stream_tag[index]);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
|
||||
unsigned int *affected_parm)
|
||||
{
|
||||
@ -1085,6 +1111,10 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force)
|
||||
verb = 0xf93;
|
||||
parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
|
||||
break;
|
||||
case VT1705CF:
|
||||
verb = 0xf82;
|
||||
parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
|
||||
break;
|
||||
default:
|
||||
return; /* other codecs are not supported */
|
||||
}
|
||||
@ -3817,6 +3847,125 @@ static int patch_vt1812(struct hda_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* patch for vt3476 */
|
||||
|
||||
static const struct hda_verb vt3476_init_verbs[] = {
|
||||
/* Enable DMic 8/16/32K */
|
||||
{0x1, 0xF7B, 0x30},
|
||||
/* Enable Boost Volume backdoor */
|
||||
{0x1, 0xFB9, 0x20},
|
||||
/* Enable AOW-MW9 path */
|
||||
{0x1, 0xFB8, 0x10},
|
||||
{ }
|
||||
};
|
||||
|
||||
static void set_widgets_power_state_vt3476(struct hda_codec *codec)
|
||||
{
|
||||
struct via_spec *spec = codec->spec;
|
||||
int imux_is_smixer;
|
||||
unsigned int parm, parm2;
|
||||
/* MUX10 (1eh) = stereo mixer */
|
||||
imux_is_smixer =
|
||||
snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 4;
|
||||
/* 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) */
|
||||
update_power_state(codec, 0x1e, parm);
|
||||
update_power_state(codec, 0x1f, parm);
|
||||
update_power_state(codec, 0x10, parm);
|
||||
update_power_state(codec, 0x11, parm);
|
||||
|
||||
/* outputs */
|
||||
/* PW3 (27h), MW3(37h), AOW3 (bh) */
|
||||
if (spec->codec_type == VT1705CF) {
|
||||
parm = AC_PWRST_D3;
|
||||
update_power_state(codec, 0x27, parm);
|
||||
update_power_state(codec, 0x37, parm);
|
||||
} else {
|
||||
parm = AC_PWRST_D3;
|
||||
set_pin_power_state(codec, 0x27, &parm);
|
||||
update_power_state(codec, 0x37, parm);
|
||||
}
|
||||
|
||||
/* PW2 (26h), MW2(36h), AOW2 (ah) */
|
||||
parm = AC_PWRST_D3;
|
||||
set_pin_power_state(codec, 0x26, &parm);
|
||||
update_power_state(codec, 0x36, parm);
|
||||
if (spec->smart51_enabled) {
|
||||
/* PW7(2bh), MW7(3bh), MUX7(1Bh) */
|
||||
set_pin_power_state(codec, 0x2b, &parm);
|
||||
update_power_state(codec, 0x3b, parm);
|
||||
update_power_state(codec, 0x1b, parm);
|
||||
}
|
||||
update_conv_power_state(codec, 0xa, parm, 2);
|
||||
|
||||
/* PW1 (25h), MW1(35h), AOW1 (9h) */
|
||||
parm = AC_PWRST_D3;
|
||||
set_pin_power_state(codec, 0x25, &parm);
|
||||
update_power_state(codec, 0x35, parm);
|
||||
if (spec->smart51_enabled) {
|
||||
/* PW6(2ah), MW6(3ah), MUX6(1ah) */
|
||||
set_pin_power_state(codec, 0x2a, &parm);
|
||||
update_power_state(codec, 0x3a, parm);
|
||||
update_power_state(codec, 0x1a, parm);
|
||||
}
|
||||
update_conv_power_state(codec, 0x9, parm, 1);
|
||||
|
||||
/* PW4 (28h), MW4 (38h), MUX4(18h), AOW3(bh)/AOW0(8h) */
|
||||
parm = AC_PWRST_D3;
|
||||
set_pin_power_state(codec, 0x28, &parm);
|
||||
update_power_state(codec, 0x38, parm);
|
||||
update_power_state(codec, 0x18, parm);
|
||||
if (spec->hp_independent_mode)
|
||||
update_conv_power_state(codec, 0xb, parm, 3);
|
||||
parm2 = parm; /* for pin 0x0b */
|
||||
|
||||
/* PW0 (24h), MW0(34h), MW9(3fh), AOW0 (8h) */
|
||||
parm = AC_PWRST_D3;
|
||||
set_pin_power_state(codec, 0x24, &parm);
|
||||
update_power_state(codec, 0x34, parm);
|
||||
if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3)
|
||||
parm = parm2;
|
||||
update_conv_power_state(codec, 0x8, parm, 0);
|
||||
/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
|
||||
update_power_state(codec, 0x3f, imux_is_smixer ? AC_PWRST_D0 : parm);
|
||||
}
|
||||
|
||||
static int patch_vt3476(struct hda_codec *codec)
|
||||
{
|
||||
struct via_spec *spec;
|
||||
int err;
|
||||
|
||||
/* create a codec specific record */
|
||||
spec = via_new_spec(codec);
|
||||
if (spec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spec->aa_mix_nid = 0x3f;
|
||||
add_secret_dac_path(codec);
|
||||
|
||||
/* automatic parse from the BIOS config */
|
||||
err = via_parse_auto_config(codec);
|
||||
if (err < 0) {
|
||||
via_free(codec);
|
||||
return err;
|
||||
}
|
||||
|
||||
spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs;
|
||||
|
||||
codec->patch_ops = via_patch_ops;
|
||||
|
||||
spec->set_widgets_power_state = set_widgets_power_state_vt3476;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch entries
|
||||
*/
|
||||
@ -3910,6 +4059,8 @@ static const struct hda_codec_preset snd_hda_preset_via[] = {
|
||||
.patch = patch_vt2002P},
|
||||
{ .id = 0x11068446, .name = "VT1802",
|
||||
.patch = patch_vt2002P},
|
||||
{ .id = 0x11064760, .name = "VT1705CF",
|
||||
.patch = patch_vt3476},
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user