aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Yau <superquad.vortex2@gmail.com>2011-01-17 05:19:03 -0500
committerTakashi Iwai <tiwai@suse.de>2011-01-18 01:43:05 -0500
commitc66ddf32dda0d5bcf9db7b4cc42ef5da7baadd3e (patch)
tree9072aa7a0f83c35358235e136ee69f8d5fe25503
parent4fe2ca14678174d9df254ae3ba2b79bacc19e2ee (diff)
ALSA: hda - Add add multi-streaming playback for AD1988
Attached a patch which add a new model to support multi-streaming playback for ad1988. playback another stereo stream through the front panel headphone on device 2 while playback through the speakers connected to rear panel on device 0 at the same time. Tested with ad1988a rev2 codec on asus P5B-V motherboard. Signed-off-by: Raymond Yau <superquad.vortex2@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_analog.c182
1 files changed, 178 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 46780670162b..34ee1169f2e0 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -46,6 +46,9 @@ struct ad198x_spec {
46 unsigned int cur_eapd; 46 unsigned int cur_eapd;
47 unsigned int need_dac_fix; 47 unsigned int need_dac_fix;
48 48
49 hda_nid_t *alt_dac_nid;
50 struct hda_pcm_stream *stream_analog_alt_playback;
51
49 /* capture */ 52 /* capture */
50 unsigned int num_adc_nids; 53 unsigned int num_adc_nids;
51 hda_nid_t *adc_nids; 54 hda_nid_t *adc_nids;
@@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = {
156 NULL 159 NULL
157}; 160};
158 161
162static const char *ad1988_6stack_fp_slave_vols[] = {
163 "Front Playback Volume",
164 "Surround Playback Volume",
165 "Center Playback Volume",
166 "LFE Playback Volume",
167 "Side Playback Volume",
168 "IEC958 Playback Volume",
169 NULL
170};
171
172static const char *ad1988_6stack_fp_slave_sws[] = {
173 "Front Playback Switch",
174 "Surround Playback Switch",
175 "Center Playback Switch",
176 "LFE Playback Switch",
177 "Side Playback Switch",
178 "IEC958 Playback Switch",
179 NULL
180};
159static void ad198x_free_kctls(struct hda_codec *codec); 181static void ad198x_free_kctls(struct hda_codec *codec);
160 182
161#ifdef CONFIG_SND_HDA_INPUT_BEEP 183#ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -309,6 +331,38 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
309 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 331 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
310} 332}
311 333
334static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
335 struct hda_codec *codec,
336 unsigned int stream_tag,
337 unsigned int format,
338 struct snd_pcm_substream *substream)
339{
340 struct ad198x_spec *spec = codec->spec;
341 snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag,
342 0, format);
343 return 0;
344}
345
346static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
347 struct hda_codec *codec,
348 struct snd_pcm_substream *substream)
349{
350 struct ad198x_spec *spec = codec->spec;
351 snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]);
352 return 0;
353}
354
355static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
356 .substreams = 1,
357 .channels_min = 2,
358 .channels_max = 2,
359 /* NID is set in ad198x_build_pcms */
360 .ops = {
361 .prepare = ad198x_alt_playback_pcm_prepare,
362 .cleanup = ad198x_alt_playback_pcm_cleanup
363 },
364};
365
312/* 366/*
313 * Digital out 367 * Digital out
314 */ 368 */
@@ -446,6 +500,17 @@ static int ad198x_build_pcms(struct hda_codec *codec)
446 } 500 }
447 } 501 }
448 502
503 if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
504 codec->num_pcms++;
505 info = spec->pcm_rec + 2;
506 info->name = "AD198x Headphone";
507 info->pcm_type = HDA_PCM_TYPE_AUDIO;
508 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
509 *spec->stream_analog_alt_playback;
510 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
511 spec->alt_dac_nid[0];
512 }
513
449 return 0; 514 return 0;
450} 515}
451 516
@@ -2015,6 +2080,7 @@ static int patch_ad1981(struct hda_codec *codec)
2015enum { 2080enum {
2016 AD1988_6STACK, 2081 AD1988_6STACK,
2017 AD1988_6STACK_DIG, 2082 AD1988_6STACK_DIG,
2083 AD1988_6STACK_DIG_FP,
2018 AD1988_3STACK, 2084 AD1988_3STACK,
2019 AD1988_3STACK_DIG, 2085 AD1988_3STACK_DIG,
2020 AD1988_LAPTOP, 2086 AD1988_LAPTOP,
@@ -2047,6 +2113,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2047 0x04, 0x05, 0x0a, 0x06 2113 0x04, 0x05, 0x0a, 0x06
2048}; 2114};
2049 2115
2116static hda_nid_t ad1988_alt_dac_nid[1] = {
2117 0x03
2118};
2119
2050static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { 2120static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2051 0x04, 0x0a, 0x06 2121 0x04, 0x0a, 0x06
2052}; 2122};
@@ -2166,6 +2236,35 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2166 { } /* end */ 2236 { } /* end */
2167}; 2237};
2168 2238
2239static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
2240 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2241
2242 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2243 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2244 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2245 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2246 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2247 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2248 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2249
2250 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2251 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2252 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2253 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2254 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2255 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2256 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2257 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2258
2259 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2260 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2261
2262 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2263 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2264
2265 { } /* end */
2266};
2267
2169/* 3-stack mode */ 2268/* 3-stack mode */
2170static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { 2269static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2171 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), 2270 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
@@ -2445,6 +2544,68 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
2445 { } 2544 { }
2446}; 2545};
2447 2546
2547static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
2548 /* Front, Surround, CLFE, side DAC; unmute as default */
2549 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2550 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2551 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2552 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2553 /* Headphone; unmute as default */
2554 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2555 /* Port-A front headphon path */
2556 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2557 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2558 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2559 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2560 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2561 /* Port-D line-out path */
2562 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2563 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2564 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2565 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2566 /* Port-F surround path */
2567 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2568 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2569 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2570 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2571 /* Port-G CLFE path */
2572 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2573 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2574 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2575 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2576 /* Port-H side path */
2577 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2578 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2579 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2580 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2581 /* Mono out path */
2582 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2583 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2584 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2585 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2586 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2587 /* Port-B front mic-in path */
2588 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2589 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2590 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2591 /* Port-C line-in path */
2592 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2593 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2594 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2595 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2596 /* Port-E mic-in path */
2597 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2598 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2599 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2600 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2601 /* Analog CD Input */
2602 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2603 /* Analog Mix output amp */
2604 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2605
2606 { }
2607};
2608
2448static struct hda_verb ad1988_capture_init_verbs[] = { 2609static struct hda_verb ad1988_capture_init_verbs[] = {
2449 /* mute analog mix */ 2610 /* mute analog mix */
2450 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2611 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -3074,13 +3235,13 @@ static int ad1988_auto_init(struct hda_codec *codec)
3074 return 0; 3235 return 0;
3075} 3236}
3076 3237
3077
3078/* 3238/*
3079 */ 3239 */
3080 3240
3081static const char *ad1988_models[AD1988_MODEL_LAST] = { 3241static const char *ad1988_models[AD1988_MODEL_LAST] = {
3082 [AD1988_6STACK] = "6stack", 3242 [AD1988_6STACK] = "6stack",
3083 [AD1988_6STACK_DIG] = "6stack-dig", 3243 [AD1988_6STACK_DIG] = "6stack-dig",
3244 [AD1988_6STACK_DIG_FP] = "6stack-dig-fp",
3084 [AD1988_3STACK] = "3stack", 3245 [AD1988_3STACK] = "3stack",
3085 [AD1988_3STACK_DIG] = "3stack-dig", 3246 [AD1988_3STACK_DIG] = "3stack-dig",
3086 [AD1988_LAPTOP] = "laptop", 3247 [AD1988_LAPTOP] = "laptop",
@@ -3140,6 +3301,7 @@ static int patch_ad1988(struct hda_codec *codec)
3140 switch (board_config) { 3301 switch (board_config) {
3141 case AD1988_6STACK: 3302 case AD1988_6STACK:
3142 case AD1988_6STACK_DIG: 3303 case AD1988_6STACK_DIG:
3304 case AD1988_6STACK_DIG_FP:
3143 spec->multiout.max_channels = 8; 3305 spec->multiout.max_channels = 8;
3144 spec->multiout.num_dacs = 4; 3306 spec->multiout.num_dacs = 4;
3145 if (is_rev2(codec)) 3307 if (is_rev2(codec))
@@ -3152,10 +3314,22 @@ static int patch_ad1988(struct hda_codec *codec)
3152 spec->mixers[0] = ad1988_6stack_mixers1_rev2; 3314 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3153 else 3315 else
3154 spec->mixers[0] = ad1988_6stack_mixers1; 3316 spec->mixers[0] = ad1988_6stack_mixers1;
3155 spec->mixers[1] = ad1988_6stack_mixers2; 3317 if (board_config == AD1988_6STACK_DIG_FP) {
3318 spec->mixers[1] = ad1988_6stack_fp_mixers;
3319 spec->slave_vols = ad1988_6stack_fp_slave_vols;
3320 spec->slave_sws = ad1988_6stack_fp_slave_sws;
3321 spec->alt_dac_nid = ad1988_alt_dac_nid;
3322 spec->stream_analog_alt_playback =
3323 &ad198x_pcm_analog_alt_playback;
3324 } else
3325 spec->mixers[1] = ad1988_6stack_mixers2;
3156 spec->num_init_verbs = 1; 3326 spec->num_init_verbs = 1;
3157 spec->init_verbs[0] = ad1988_6stack_init_verbs; 3327 if (board_config == AD1988_6STACK_DIG_FP)
3158 if (board_config == AD1988_6STACK_DIG) { 3328 spec->init_verbs[0] = ad1988_6stack_fp_init_verbs;
3329 else
3330 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3331 if ((board_config == AD1988_6STACK_DIG) ||
3332 (board_config == AD1988_6STACK_DIG_FP)) {
3159 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; 3333 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3160 spec->dig_in_nid = AD1988_SPDIF_IN; 3334 spec->dig_in_nid = AD1988_SPDIF_IN;
3161 } 3335 }