|
@@ -46,6 +46,9 @@ struct ad198x_spec {
|
|
|
unsigned int cur_eapd;
|
|
|
unsigned int need_dac_fix;
|
|
|
|
|
|
+ hda_nid_t *alt_dac_nid;
|
|
|
+ struct hda_pcm_stream *stream_analog_alt_playback;
|
|
|
+
|
|
|
/* capture */
|
|
|
unsigned int num_adc_nids;
|
|
|
hda_nid_t *adc_nids;
|
|
@@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = {
|
|
|
NULL
|
|
|
};
|
|
|
|
|
|
+static const char *ad1988_6stack_fp_slave_vols[] = {
|
|
|
+ "Front Playback Volume",
|
|
|
+ "Surround Playback Volume",
|
|
|
+ "Center Playback Volume",
|
|
|
+ "LFE Playback Volume",
|
|
|
+ "Side Playback Volume",
|
|
|
+ "IEC958 Playback Volume",
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+static const char *ad1988_6stack_fp_slave_sws[] = {
|
|
|
+ "Front Playback Switch",
|
|
|
+ "Surround Playback Switch",
|
|
|
+ "Center Playback Switch",
|
|
|
+ "LFE Playback Switch",
|
|
|
+ "Side Playback Switch",
|
|
|
+ "IEC958 Playback Switch",
|
|
|
+ NULL
|
|
|
+};
|
|
|
static void ad198x_free_kctls(struct hda_codec *codec);
|
|
|
|
|
|
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
|
@@ -309,6 +331,38 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
|
|
|
}
|
|
|
|
|
|
+static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ unsigned int stream_tag,
|
|
|
+ unsigned int format,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ struct ad198x_spec *spec = codec->spec;
|
|
|
+ snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag,
|
|
|
+ 0, format);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
|
|
|
+ struct hda_codec *codec,
|
|
|
+ struct snd_pcm_substream *substream)
|
|
|
+{
|
|
|
+ struct ad198x_spec *spec = codec->spec;
|
|
|
+ snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static 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 = {
|
|
|
+ .prepare = ad198x_alt_playback_pcm_prepare,
|
|
|
+ .cleanup = ad198x_alt_playback_pcm_cleanup
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Digital out
|
|
|
*/
|
|
@@ -446,6 +500,17 @@ static int ad198x_build_pcms(struct hda_codec *codec)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
|
|
|
+ codec->num_pcms++;
|
|
|
+ info = spec->pcm_rec + 2;
|
|
|
+ info->name = "AD198x Headphone";
|
|
|
+ info->pcm_type = HDA_PCM_TYPE_AUDIO;
|
|
|
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
|
|
|
+ *spec->stream_analog_alt_playback;
|
|
|
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
|
|
|
+ spec->alt_dac_nid[0];
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2015,6 +2080,7 @@ 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,
|
|
@@ -2047,6 +2113,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
|
|
|
0x04, 0x05, 0x0a, 0x06
|
|
|
};
|
|
|
|
|
|
+static hda_nid_t ad1988_alt_dac_nid[1] = {
|
|
|
+ 0x03
|
|
|
+};
|
|
|
+
|
|
|
static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
|
|
|
0x04, 0x0a, 0x06
|
|
|
};
|
|
@@ -2166,6 +2236,35 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
|
|
|
{ } /* end */
|
|
|
};
|
|
|
|
|
|
+static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
|
|
|
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
|
|
|
+
|
|
|
+ HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
|
|
|
+ HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
|
|
|
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
|
|
|
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
|
|
|
+ HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
|
|
|
+ HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
|
|
|
+ HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
|
|
|
+
|
|
|
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
|
|
|
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
|
|
|
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
|
|
|
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
|
|
|
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
|
|
|
+
|
|
|
+ HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
|
|
|
+ HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
|
|
|
+
|
|
|
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
|
|
|
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
|
|
|
+
|
|
|
+ { } /* end */
|
|
|
+};
|
|
|
+
|
|
|
/* 3-stack mode */
|
|
|
static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
|
|
|
HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
|
|
@@ -2445,6 +2544,68 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
|
|
|
{ }
|
|
|
};
|
|
|
|
|
|
+static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
|
|
|
+ /* Front, Surround, CLFE, side DAC; unmute as default */
|
|
|
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ /* Headphone; unmute as default */
|
|
|
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ /* Port-A front headphon path */
|
|
|
+ {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
|
|
|
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
|
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
|
|
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
|
|
|
+ /* Port-D line-out path */
|
|
|
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
|
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
|
|
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
+ /* Port-F surround path */
|
|
|
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
|
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
|
|
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
+ /* Port-G CLFE path */
|
|
|
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
|
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
|
|
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
+ /* Port-H side path */
|
|
|
+ {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
|
+ {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
|
|
+ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
|
|
|
+ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
+ /* Mono out path */
|
|
|
+ {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
|
|
|
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
|
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
|
|
|
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
|
|
|
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
|
|
|
+ /* Port-B front mic-in path */
|
|
|
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
|
|
+ {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
|
|
+ /* Port-C line-in path */
|
|
|
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
|
|
+ {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
|
|
+ {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
|
|
|
+ /* Port-E mic-in path */
|
|
|
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
|
|
|
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
|
|
|
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
|
|
|
+ {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
|
|
|
+ /* Analog CD Input */
|
|
|
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
|
|
|
+ /* Analog Mix output amp */
|
|
|
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
|
|
|
+
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
static struct hda_verb ad1988_capture_init_verbs[] = {
|
|
|
/* mute analog mix */
|
|
|
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
|
|
@@ -3074,13 +3235,13 @@ static int ad1988_auto_init(struct hda_codec *codec)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/*
|
|
|
*/
|
|
|
|
|
|
static const char *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",
|
|
@@ -3140,6 +3301,7 @@ static int patch_ad1988(struct hda_codec *codec)
|
|
|
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))
|
|
@@ -3152,10 +3314,22 @@ static int patch_ad1988(struct hda_codec *codec)
|
|
|
spec->mixers[0] = ad1988_6stack_mixers1_rev2;
|
|
|
else
|
|
|
spec->mixers[0] = ad1988_6stack_mixers1;
|
|
|
- spec->mixers[1] = ad1988_6stack_mixers2;
|
|
|
+ if (board_config == AD1988_6STACK_DIG_FP) {
|
|
|
+ spec->mixers[1] = ad1988_6stack_fp_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;
|
|
|
+ } else
|
|
|
+ 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) {
|
|
|
+ if (board_config == AD1988_6STACK_DIG_FP)
|
|
|
+ spec->init_verbs[0] = ad1988_6stack_fp_init_verbs;
|
|
|
+ else
|
|
|
+ spec->init_verbs[0] = ad1988_6stack_init_verbs;
|
|
|
+ if ((board_config == AD1988_6STACK_DIG) ||
|
|
|
+ (board_config == AD1988_6STACK_DIG_FP)) {
|
|
|
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
|
|
|
spec->dig_in_nid = AD1988_SPDIF_IN;
|
|
|
}
|