ALSA: HDA VIA: Add smart5.1 function.

Smart 5.1 is for 3-jacks model, to reuse input pins as outputs.
While off, they act as "line out" / "line in" / "mic in".
While on, they acts as "line out" / "back left/right" / "center/lfe".

Signed-off-by: Lydia Wang <lydiawang@viatech.com.cn>
Signed-off-by: Logan Li <loganli@viatech.com.cn>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Lydia Wang 2009-10-10 19:07:52 +08:00 committed by Takashi Iwai
parent cdc1784d49
commit 1564b2878f

View file

@ -211,7 +211,7 @@ static struct snd_kcontrol_new vt1708_control_templates[] = {
struct via_spec {
/* codec parameterization */
struct snd_kcontrol_new *mixers[3];
struct snd_kcontrol_new *mixers[4];
unsigned int num_mixers;
struct hda_verb *init_verbs[5];
@ -253,6 +253,7 @@ struct via_spec {
const struct hda_input_mux *hp_mux;
unsigned int hp_independent_mode;
unsigned int hp_independent_mode_index;
unsigned int smart51_enabled;
enum VIA_HDA_CODEC codec_type;
@ -390,6 +391,8 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
}
}
static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
unsigned int *affected_parm)
{
@ -400,9 +403,10 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
& AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
unsigned present = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0) >> 31;
if ((no_presence || present) && get_defcfg_connect(def_conf)
!= AC_JACK_PORT_NONE) {
struct via_spec *spec = codec->spec;
if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
|| ((no_presence || present)
&& get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
*affected_parm = AC_PWRST_D0; /* if it's connected */
parm = AC_PWRST_D0;
} else
@ -657,6 +661,167 @@ static struct snd_kcontrol_new via_hp_mixer[] = {
{ } /* end */
};
static void notify_aa_path_ctls(struct hda_codec *codec)
{
int i;
struct snd_ctl_elem_id id;
const char *labels[] = {"Mic", "Front Mic", "Line"};
memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
for (i = 0; i < ARRAY_SIZE(labels); i++) {
sprintf(id.name, "%s Playback Volume", labels[i]);
snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
&id);
}
}
static void mute_aa_path(struct hda_codec *codec, int mute)
{
struct via_spec *spec = codec->spec;
hda_nid_t nid_mixer;
int start_idx;
int end_idx;
int i;
/* get nid of MW0 and start & end index */
switch (spec->codec_type) {
case VT1708:
nid_mixer = 0x17;
start_idx = 2;
end_idx = 4;
break;
case VT1709_10CH:
case VT1709_6CH:
nid_mixer = 0x18;
start_idx = 2;
end_idx = 4;
break;
case VT1708B_8CH:
case VT1708B_4CH:
case VT1708S:
nid_mixer = 0x16;
start_idx = 2;
end_idx = 4;
break;
default:
return;
}
/* check AA path's mute status */
for (i = start_idx; i <= end_idx; i++) {
int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
HDA_AMP_MUTE, val);
}
}
static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
{
int res = 0;
int index;
for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
if (pin == spec->autocfg.input_pins[index]) {
res = 1;
break;
}
}
return res;
}
static int via_smart51_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static int via_smart51_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
int on = 1;
int i;
for (i = 0; i < ARRAY_SIZE(index); i++) {
hda_nid_t nid = spec->autocfg.input_pins[index[i]];
if (nid) {
int ctl =
snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL,
0);
if (i == AUTO_PIN_FRONT_MIC
&& spec->hp_independent_mode)
continue; /* ignore FMic for independent HP */
if (ctl & AC_PINCTL_IN_EN
&& !(ctl & AC_PINCTL_OUT_EN))
on = 0;
}
}
*ucontrol->value.integer.value = on;
return 0;
}
static int via_smart51_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
int out_in = *ucontrol->value.integer.value
? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
int i;
for (i = 0; i < ARRAY_SIZE(index); i++) {
hda_nid_t nid = spec->autocfg.input_pins[index[i]];
if (i == AUTO_PIN_FRONT_MIC
&& spec->hp_independent_mode)
continue; /* don't retask FMic for independent HP */
if (nid) {
unsigned int parm = snd_hda_codec_read(
codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
parm |= out_in;
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
parm);
if (out_in == AC_PINCTL_OUT_EN) {
mute_aa_path(codec, 1);
notify_aa_path_ctls(codec);
}
}
if (i == AUTO_PIN_FRONT_MIC) {
if (spec->codec_type == VT1708S) {
/* input = index 1 (AOW3) */
snd_hda_codec_write(
codec, nid, 0,
AC_VERB_SET_CONNECT_SEL, 1);
snd_hda_codec_amp_stereo(
codec, nid, HDA_OUTPUT,
0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
}
}
}
spec->smart51_enabled = *ucontrol->value.integer.value;
set_jack_power_state(codec);
return 1;
}
static struct snd_kcontrol_new via_smart51_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Smart 5.1",
.count = 1,
.info = via_smart51_info,
.get = via_smart51_get,
.put = via_smart51_put,
},
{} /* end */
};
/* capture mixer elements */
static struct snd_kcontrol_new vt1708_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@ -1587,6 +1752,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
@ -2087,6 +2253,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
@ -2649,6 +2816,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
@ -3142,6 +3310,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}