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:
Lydia Wang 2012-12-10 18:28:11 +08:00 committed by Takashi Iwai
parent 97768a8e65
commit 43737e0ae9

View File

@ -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 */
};