mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 01:51:53 +00:00
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:
parent
cdc1784d49
commit
1564b2878f
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user