|
@@ -48,6 +48,8 @@ struct ad198x_spec {
|
|
|
|
|
|
const hda_nid_t *alt_dac_nid;
|
|
|
const struct hda_pcm_stream *stream_analog_alt_playback;
|
|
|
+ int independent_hp;
|
|
|
+ int num_active_streams;
|
|
|
|
|
|
/* capture */
|
|
|
unsigned int num_adc_nids;
|
|
@@ -302,6 +304,72 @@ static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static void activate_ctl(struct hda_codec *codec, const char *name, int active)
|
|
|
+{
|
|
|
+ struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
|
|
|
+ if (ctl) {
|
|
|
+ ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
|
|
+ ctl->vd[0].access |= active ? 0 :
|
|
|
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
|
|
+ ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
|
|
|
+ ctl->vd[0].access |= active ?
|
|
|
+ SNDRV_CTL_ELEM_ACCESS_WRITE : 0;
|
|
|
+ snd_ctl_notify(codec->bus->card,
|
|
|
+ SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void set_stream_active(struct hda_codec *codec, bool active)
|
|
|
+{
|
|
|
+ struct ad198x_spec *spec = codec->spec;
|
|
|
+ if (active)
|
|
|
+ spec->num_active_streams++;
|
|
|
+ else
|
|
|
+ spec->num_active_streams--;
|
|
|
+ activate_ctl(codec, "Independent HP", spec->num_active_streams == 0);
|
|
|
+}
|
|
|
+
|
|
|
+static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_info *uinfo)
|
|
|
+{
|
|
|
+ static const char * const texts[] = { "OFF", "ON", NULL};
|
|
|
+ int index;
|
|
|
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
|
|
|
+ uinfo->count = 1;
|
|
|
+ uinfo->value.enumerated.items = 2;
|
|
|
+ index = uinfo->value.enumerated.item;
|
|
|
+ if (index >= 2)
|
|
|
+ index = 1;
|
|
|
+ strcpy(uinfo->value.enumerated.name, texts[index]);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
+ struct ad198x_spec *spec = codec->spec;
|
|
|
+ ucontrol->value.enumerated.item[0] = spec->independent_hp;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
|
+ struct ad198x_spec *spec = codec->spec;
|
|
|
+ unsigned int select = ucontrol->value.enumerated.item[0];
|
|
|
+ if (spec->independent_hp != select) {
|
|
|
+ spec->independent_hp = select;
|
|
|
+ if (spec->independent_hp)
|
|
|
+ spec->multiout.hp_nid = 0;
|
|
|
+ else
|
|
|
+ spec->multiout.hp_nid = spec->alt_dac_nid[0];
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Analog playback callbacks
|
|
|
*/
|
|
@@ -310,8 +378,15 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
|
|
struct snd_pcm_substream *substream)
|
|
|
{
|
|
|
struct ad198x_spec *spec = codec->spec;
|
|
|
- return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
|
|
|
+ int err;
|
|
|
+ set_stream_active(codec, true);
|
|
|
+ err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
|
|
|
hinfo);
|
|
|
+ if (err < 0) {
|
|
|
+ set_stream_active(codec, false);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
@@ -333,11 +408,41 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
|
|
|
}
|
|
|
|
|
|
+static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ set_stream_active(codec, false);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ struct ad198x_spec *spec = codec->spec;
|
|
|
+ if (!spec->independent_hp)
|
|
|
+ return -EBUSY;
|
|
|
+ set_stream_active(codec, true);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ set_stream_active(codec, false);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
|
|
|
.substreams = 1,
|
|
|
.channels_min = 2,
|
|
|
.channels_max = 2,
|
|
|
- /* NID is set in ad198x_build_pcms */
|
|
|
+ .ops = {
|
|
|
+ .open = ad1988_alt_playback_pcm_open,
|
|
|
+ .close = ad1988_alt_playback_pcm_close
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -402,7 +507,6 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
*/
|
|
|
static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
|
|
@@ -413,7 +517,8 @@ static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
|
|
|
.ops = {
|
|
|
.open = ad198x_playback_pcm_open,
|
|
|
.prepare = ad198x_playback_pcm_prepare,
|
|
|
- .cleanup = ad198x_playback_pcm_cleanup
|
|
|
+ .cleanup = ad198x_playback_pcm_cleanup,
|
|
|
+ .close = ad198x_playback_pcm_close
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -2058,7 +2163,6 @@ static int patch_ad1981(struct hda_codec *codec)
|
|
|
enum {
|
|
|
AD1988_6STACK,
|
|
|
AD1988_6STACK_DIG,
|
|
|
- AD1988_6STACK_DIG_FP,
|
|
|
AD1988_3STACK,
|
|
|
AD1988_3STACK_DIG,
|
|
|
AD1988_LAPTOP,
|
|
@@ -2168,6 +2272,17 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static const struct snd_kcontrol_new ad1988_hp_mixers[] = {
|
|
|
+ {
|
|
|
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
+ .name = "Independent HP",
|
|
|
+ .info = ad1988_independent_hp_info,
|
|
|
+ .get = ad1988_independent_hp_get,
|
|
|
+ .put = ad1988_independent_hp_put,
|
|
|
+ },
|
|
|
+ { } /* end */
|
|
|
+};
|
|
|
+
|
|
|
/* 6-stack mode */
|
|
|
static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
|
|
|
HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
|
|
@@ -2211,7 +2326,6 @@ static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
|
|
|
|
|
|
HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
|
|
|
HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
|
|
|
-
|
|
|
{ } /* end */
|
|
|
};
|
|
|
|
|
@@ -3147,7 +3261,6 @@ static int ad1988_auto_init(struct hda_codec *codec)
|
|
|
static const char * const ad1988_models[AD1988_MODEL_LAST] = {
|
|
|
[AD1988_6STACK] = "6stack",
|
|
|
[AD1988_6STACK_DIG] = "6stack-dig",
|
|
|
- [AD1988_6STACK_DIG_FP] = "6stack-dig-fp",
|
|
|
[AD1988_3STACK] = "3stack",
|
|
|
[AD1988_3STACK_DIG] = "3stack-dig",
|
|
|
[AD1988_LAPTOP] = "laptop",
|
|
@@ -3206,11 +3319,10 @@ static int patch_ad1988(struct hda_codec *codec)
|
|
|
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
|
|
|
|
|
|
if (!spec->multiout.hp_nid)
|
|
|
- spec->multiout.hp_nid = 0x03;
|
|
|
+ spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
|
|
|
switch (board_config) {
|
|
|
case AD1988_6STACK:
|
|
|
case AD1988_6STACK_DIG:
|
|
|
- case AD1988_6STACK_DIG_FP:
|
|
|
spec->multiout.max_channels = 8;
|
|
|
spec->multiout.num_dacs = 4;
|
|
|
if (is_rev2(codec))
|
|
@@ -3226,16 +3338,7 @@ static int patch_ad1988(struct hda_codec *codec)
|
|
|
spec->mixers[1] = ad1988_6stack_mixers2;
|
|
|
spec->num_init_verbs = 1;
|
|
|
spec->init_verbs[0] = ad1988_6stack_init_verbs;
|
|
|
- if (board_config == AD1988_6STACK_DIG_FP) {
|
|
|
- spec->multiout.hp_nid = 0;
|
|
|
- spec->slave_vols = ad1988_6stack_fp_slave_vols;
|
|
|
- spec->slave_sws = ad1988_6stack_fp_slave_sws;
|
|
|
- spec->alt_dac_nid = ad1988_alt_dac_nid;
|
|
|
- spec->stream_analog_alt_playback =
|
|
|
- &ad198x_pcm_analog_alt_playback;
|
|
|
- }
|
|
|
- if ((board_config == AD1988_6STACK_DIG) ||
|
|
|
- (board_config == AD1988_6STACK_DIG_FP)) {
|
|
|
+ if (board_config == AD1988_6STACK_DIG) {
|
|
|
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
|
|
|
spec->dig_in_nid = AD1988_SPDIF_IN;
|
|
|
}
|
|
@@ -3278,6 +3381,15 @@ static int patch_ad1988(struct hda_codec *codec)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ if (spec->autocfg.hp_pins[0]) {
|
|
|
+ spec->mixers[spec->num_mixers++] = ad1988_hp_mixers;
|
|
|
+ spec->slave_vols = ad1988_6stack_fp_slave_vols;
|
|
|
+ spec->slave_sws = ad1988_6stack_fp_slave_sws;
|
|
|
+ spec->alt_dac_nid = ad1988_alt_dac_nid;
|
|
|
+ spec->stream_analog_alt_playback =
|
|
|
+ &ad198x_pcm_analog_alt_playback;
|
|
|
+ }
|
|
|
+
|
|
|
spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
|
|
|
spec->adc_nids = ad1988_adc_nids;
|
|
|
spec->capsrc_nids = ad1988_capsrc_nids;
|