mirror of https://gitee.com/openkylin/linux.git
ALSA: hda - Fix re-routing of HP-independent mode in patch_via.c
Re-route the whole output path when HP-independent mode is changed. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
a00a5fad9d
commit
8df2a3129d
|
@ -138,9 +138,7 @@ struct via_spec {
|
||||||
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
|
||||||
|
|
||||||
/* HP mode source */
|
/* HP mode source */
|
||||||
const struct hda_input_mux *hp_mux;
|
|
||||||
unsigned int hp_independent_mode;
|
unsigned int hp_independent_mode;
|
||||||
unsigned int hp_independent_mode_index;
|
|
||||||
unsigned int dmic_enabled;
|
unsigned int dmic_enabled;
|
||||||
unsigned int no_pin_power_ctl;
|
unsigned int no_pin_power_ctl;
|
||||||
enum VIA_HDA_CODEC codec_type;
|
enum VIA_HDA_CODEC codec_type;
|
||||||
|
@ -406,6 +404,24 @@ static int __get_connection_index(struct hda_codec *codec, hda_nid_t mux,
|
||||||
#define get_connection_index(codec, mux, nid) \
|
#define get_connection_index(codec, mux, nid) \
|
||||||
__get_connection_index(codec, mux, nid, NULL)
|
__get_connection_index(codec, mux, nid, NULL)
|
||||||
|
|
||||||
|
static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
|
||||||
|
unsigned int mask)
|
||||||
|
{
|
||||||
|
unsigned int caps = get_wcaps(codec, nid);
|
||||||
|
if (dir == HDA_INPUT)
|
||||||
|
caps &= AC_WCAP_IN_AMP;
|
||||||
|
else
|
||||||
|
caps &= AC_WCAP_OUT_AMP;
|
||||||
|
if (!caps)
|
||||||
|
return false;
|
||||||
|
if (query_amp_caps(codec, nid, dir) & mask)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define have_vol_or_mute(codec, nid, dir) \
|
||||||
|
check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE)
|
||||||
|
|
||||||
/* unmute input amp and select the specificed source */
|
/* unmute input amp and select the specificed source */
|
||||||
static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid,
|
static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid,
|
||||||
hda_nid_t src, hda_nid_t mix)
|
hda_nid_t src, hda_nid_t mix)
|
||||||
|
@ -423,22 +439,20 @@ static void unmute_and_select(struct hda_codec *codec, hda_nid_t nid,
|
||||||
AC_VERB_SET_CONNECT_SEL, idx);
|
AC_VERB_SET_CONNECT_SEL, idx);
|
||||||
|
|
||||||
/* unmute if the input amp is present */
|
/* unmute if the input amp is present */
|
||||||
if (query_amp_caps(codec, nid, HDA_INPUT) &
|
if (have_vol_or_mute(codec, nid, HDA_INPUT))
|
||||||
(AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE))
|
|
||||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||||
AMP_IN_UNMUTE(idx));
|
AMP_IN_UNMUTE(idx));
|
||||||
|
|
||||||
/* unmute the src output */
|
/* unmute the src output */
|
||||||
if (query_amp_caps(codec, src, HDA_OUTPUT) &
|
if (have_vol_or_mute(codec, src, HDA_OUTPUT))
|
||||||
(AC_AMPCAP_NUM_STEPS | AC_AMPCAP_MUTE))
|
|
||||||
snd_hda_codec_write(codec, src, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
snd_hda_codec_write(codec, src, 0, AC_VERB_SET_AMP_GAIN_MUTE,
|
||||||
AMP_OUT_UNMUTE);
|
AMP_OUT_UNMUTE);
|
||||||
|
|
||||||
/* unmute AA-path if present */
|
/* unmute AA-path if present */
|
||||||
if (!mix)
|
if (!mix || mix == src)
|
||||||
return;
|
return;
|
||||||
idx = __get_connection_index(codec, nid, mix, NULL);
|
idx = __get_connection_index(codec, nid, mix, NULL);
|
||||||
if (idx >= 0)
|
if (idx >= 0 && have_vol_or_mute(codec, nid, HDA_INPUT))
|
||||||
snd_hda_codec_write(codec, nid, 0,
|
snd_hda_codec_write(codec, nid, 0,
|
||||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||||
AMP_IN_UNMUTE(idx));
|
AMP_IN_UNMUTE(idx));
|
||||||
|
@ -694,9 +708,16 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
|
||||||
static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
|
static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_info *uinfo)
|
struct snd_ctl_elem_info *uinfo)
|
||||||
{
|
{
|
||||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
static const char * const texts[] = { "OFF", "ON" };
|
||||||
struct via_spec *spec = codec->spec;
|
|
||||||
return snd_hda_input_mux_info(spec->hp_mux, uinfo);
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
||||||
|
uinfo->count = 1;
|
||||||
|
uinfo->value.enumerated.items = 2;
|
||||||
|
if (uinfo->value.enumerated.item >= 2)
|
||||||
|
uinfo->value.enumerated.item = 1;
|
||||||
|
strcpy(uinfo->value.enumerated.name,
|
||||||
|
texts[uinfo->value.enumerated.item]);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
|
static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
|
||||||
|
@ -714,12 +735,28 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
|
||||||
{
|
{
|
||||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
struct via_spec *spec = codec->spec;
|
struct via_spec *spec = codec->spec;
|
||||||
hda_nid_t nid = kcontrol->private_value;
|
hda_nid_t nid, src;
|
||||||
unsigned int pinsel = ucontrol->value.enumerated.item[0];
|
int i, idx, num_conns;
|
||||||
/* Get Independent Mode index of headphone pin widget */
|
struct nid_path *path;
|
||||||
spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
|
|
||||||
? 1 : 0;
|
spec->hp_independent_mode = !!ucontrol->value.enumerated.item[0];
|
||||||
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
|
if (spec->hp_independent_mode)
|
||||||
|
path = &spec->hp_path;
|
||||||
|
else
|
||||||
|
path = &spec->hp_dep_path;
|
||||||
|
|
||||||
|
/* re-route the output path */
|
||||||
|
for (i = path->depth - 1; i > 0; i--) {
|
||||||
|
nid = path->path[i];
|
||||||
|
src = path->path[i - 1];
|
||||||
|
idx = __get_connection_index(codec, nid, src, &num_conns);
|
||||||
|
if (idx < 0)
|
||||||
|
continue;
|
||||||
|
if (num_conns > 1 &&
|
||||||
|
get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX)
|
||||||
|
snd_hda_codec_write(codec, nid, 0,
|
||||||
|
AC_VERB_SET_CONNECT_SEL, idx);
|
||||||
|
}
|
||||||
|
|
||||||
/* update jack power state */
|
/* update jack power state */
|
||||||
set_widgets_power_state(codec);
|
set_widgets_power_state(codec);
|
||||||
|
@ -746,7 +783,6 @@ static int via_hp_build(struct hda_codec *codec)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
|
knew->subdevice = HDA_SUBDEV_NID_FLAG | nid;
|
||||||
knew->private_value = nid;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1622,9 +1658,9 @@ static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
|
||||||
hda_nid_t nid;
|
hda_nid_t nid;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (dac && query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
|
if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
|
||||||
nid = dac;
|
nid = dac;
|
||||||
else if (query_amp_caps(codec, pin, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
|
else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS))
|
||||||
nid = pin;
|
nid = pin;
|
||||||
else
|
else
|
||||||
nid = 0;
|
nid = 0;
|
||||||
|
@ -1636,9 +1672,9 @@ static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dac && query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_MUTE)
|
if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
|
||||||
nid = dac;
|
nid = dac;
|
||||||
else if (query_amp_caps(codec, pin, HDA_OUTPUT) & AC_AMPCAP_MUTE)
|
else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE))
|
||||||
nid = pin;
|
nid = pin;
|
||||||
else
|
else
|
||||||
nid = 0;
|
nid = 0;
|
||||||
|
@ -1741,19 +1777,6 @@ static int via_auto_create_multi_out_ctls(struct hda_codec *codec)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_hp_imux(struct via_spec *spec)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct hda_input_mux *imux = &spec->private_imux[1];
|
|
||||||
static const char * const texts[] = { "OFF", "ON", NULL};
|
|
||||||
|
|
||||||
/* for hp mode select */
|
|
||||||
for (i = 0; texts[i]; i++)
|
|
||||||
snd_hda_add_imux_item(imux, texts[i], i, NULL);
|
|
||||||
|
|
||||||
spec->hp_mux = &spec->private_imux[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
|
static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
|
||||||
{
|
{
|
||||||
struct via_spec *spec = codec->spec;
|
struct via_spec *spec = codec->spec;
|
||||||
|
@ -1762,18 +1785,14 @@ static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
|
||||||
if (!pin)
|
if (!pin)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (parse_output_path(codec, pin, 0, &spec->hp_path)) {
|
if (parse_output_path(codec, pin, 0, &spec->hp_path))
|
||||||
spec->hp_dac_nid = spec->hp_path.path[0];
|
spec->hp_dac_nid = spec->hp_path.path[0];
|
||||||
spec->hp_independent_mode_index = spec->hp_path.idx[0];
|
|
||||||
create_hp_imux(spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
|
if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT],
|
||||||
&spec->hp_dep_path) &&
|
&spec->hp_dep_path) &&
|
||||||
!spec->hp_dac_nid)
|
!spec->hp_dac_nid)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3);
|
err = create_ch_ctls(codec, "Headphone", pin, spec->hp_dac_nid, 3);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
@ -2068,7 +2087,7 @@ static int via_parse_auto_config(struct hda_codec *codec)
|
||||||
|
|
||||||
spec->input_mux = &spec->private_imux[0];
|
spec->input_mux = &spec->private_imux[0];
|
||||||
|
|
||||||
if (spec->hp_mux) {
|
if (spec->hp_dac_nid && spec->hp_dep_path.depth) {
|
||||||
err = via_hp_build(codec);
|
err = via_hp_build(codec);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Reference in New Issue