diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 133 |
1 files changed, 101 insertions, 32 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index da6874d3988c..d7d636decef8 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -28,15 +28,38 @@ | |||
28 | #include "hda_local.h" | 28 | #include "hda_local.h" |
29 | 29 | ||
30 | struct ad198x_spec { | 30 | struct ad198x_spec { |
31 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ | 31 | snd_kcontrol_new_t *mixers[5]; |
32 | struct hda_multi_out multiout; /* playback */ | 32 | int num_mixers; |
33 | hda_nid_t adc_nid; | 33 | |
34 | const struct hda_verb *init_verbs[3]; /* initialization verbs | ||
35 | * don't forget NULL termination! | ||
36 | */ | ||
37 | unsigned int num_init_verbs; | ||
38 | |||
39 | /* playback */ | ||
40 | struct hda_multi_out multiout; /* playback set-up | ||
41 | * max_channels, dacs must be set | ||
42 | * dig_out_nid and hp_nid are optional | ||
43 | */ | ||
44 | |||
45 | /* capture */ | ||
46 | unsigned int num_adc_nids; | ||
47 | hda_nid_t *adc_nids; | ||
48 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | ||
49 | |||
50 | /* capture source */ | ||
34 | const struct hda_input_mux *input_mux; | 51 | const struct hda_input_mux *input_mux; |
35 | unsigned int cur_mux; /* capture source */ | 52 | unsigned int cur_mux[3]; |
53 | |||
54 | /* channel model */ | ||
55 | const struct alc_channel_mode *channel_mode; | ||
56 | int num_channel_mode; | ||
57 | |||
58 | /* PCM information */ | ||
59 | struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ | ||
60 | |||
61 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ | ||
36 | unsigned int spdif_route; | 62 | unsigned int spdif_route; |
37 | snd_kcontrol_new_t *mixers; | ||
38 | const struct hda_verb *init_verbs; | ||
39 | struct hda_pcm pcm_rec[2]; /* PCM information */ | ||
40 | }; | 63 | }; |
41 | 64 | ||
42 | /* | 65 | /* |
@@ -54,8 +77,9 @@ static int ad198x_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u | |||
54 | { | 77 | { |
55 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 78 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
56 | struct ad198x_spec *spec = codec->spec; | 79 | struct ad198x_spec *spec = codec->spec; |
80 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
57 | 81 | ||
58 | ucontrol->value.enumerated.item[0] = spec->cur_mux; | 82 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; |
59 | return 0; | 83 | return 0; |
60 | } | 84 | } |
61 | 85 | ||
@@ -63,9 +87,10 @@ static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u | |||
63 | { | 87 | { |
64 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 88 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
65 | struct ad198x_spec *spec = codec->spec; | 89 | struct ad198x_spec *spec = codec->spec; |
90 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
66 | 91 | ||
67 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 92 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
68 | spec->adc_nid, &spec->cur_mux); | 93 | spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); |
69 | } | 94 | } |
70 | 95 | ||
71 | /* | 96 | /* |
@@ -74,22 +99,34 @@ static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u | |||
74 | static int ad198x_init(struct hda_codec *codec) | 99 | static int ad198x_init(struct hda_codec *codec) |
75 | { | 100 | { |
76 | struct ad198x_spec *spec = codec->spec; | 101 | struct ad198x_spec *spec = codec->spec; |
77 | snd_hda_sequence_write(codec, spec->init_verbs); | 102 | int i; |
103 | |||
104 | for (i = 0; i < spec->num_init_verbs; i++) | ||
105 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | ||
78 | return 0; | 106 | return 0; |
79 | } | 107 | } |
80 | 108 | ||
81 | static int ad198x_build_controls(struct hda_codec *codec) | 109 | static int ad198x_build_controls(struct hda_codec *codec) |
82 | { | 110 | { |
83 | struct ad198x_spec *spec = codec->spec; | 111 | struct ad198x_spec *spec = codec->spec; |
112 | unsigned int i; | ||
84 | int err; | 113 | int err; |
85 | 114 | ||
86 | err = snd_hda_add_new_ctls(codec, spec->mixers); | 115 | for (i = 0; i < spec->num_mixers; i++) { |
87 | if (err < 0) | 116 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
88 | return err; | 117 | if (err < 0) |
89 | if (spec->multiout.dig_out_nid) | 118 | return err; |
119 | } | ||
120 | if (spec->multiout.dig_out_nid) { | ||
90 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 121 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); |
91 | if (err < 0) | 122 | if (err < 0) |
92 | return err; | 123 | return err; |
124 | } | ||
125 | if (spec->dig_in_nid) { | ||
126 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
127 | if (err < 0) | ||
128 | return err; | ||
129 | } | ||
93 | return 0; | 130 | return 0; |
94 | } | 131 | } |
95 | 132 | ||
@@ -152,7 +189,8 @@ static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
152 | snd_pcm_substream_t *substream) | 189 | snd_pcm_substream_t *substream) |
153 | { | 190 | { |
154 | struct ad198x_spec *spec = codec->spec; | 191 | struct ad198x_spec *spec = codec->spec; |
155 | snd_hda_codec_setup_stream(codec, spec->adc_nid, stream_tag, 0, format); | 192 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], |
193 | stream_tag, 0, format); | ||
156 | return 0; | 194 | return 0; |
157 | } | 195 | } |
158 | 196 | ||
@@ -161,7 +199,8 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
161 | snd_pcm_substream_t *substream) | 199 | snd_pcm_substream_t *substream) |
162 | { | 200 | { |
163 | struct ad198x_spec *spec = codec->spec; | 201 | struct ad198x_spec *spec = codec->spec; |
164 | snd_hda_codec_setup_stream(codec, spec->adc_nid, 0, 0, 0); | 202 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], |
203 | 0, 0, 0); | ||
165 | return 0; | 204 | return 0; |
166 | } | 205 | } |
167 | 206 | ||
@@ -171,7 +210,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
171 | static struct hda_pcm_stream ad198x_pcm_analog_playback = { | 210 | static struct hda_pcm_stream ad198x_pcm_analog_playback = { |
172 | .substreams = 1, | 211 | .substreams = 1, |
173 | .channels_min = 2, | 212 | .channels_min = 2, |
174 | .channels_max = 6, | 213 | .channels_max = 6, /* changed later */ |
175 | .nid = 0, /* fill later */ | 214 | .nid = 0, /* fill later */ |
176 | .ops = { | 215 | .ops = { |
177 | .open = ad198x_playback_pcm_open, | 216 | .open = ad198x_playback_pcm_open, |
@@ -181,7 +220,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_playback = { | |||
181 | }; | 220 | }; |
182 | 221 | ||
183 | static struct hda_pcm_stream ad198x_pcm_analog_capture = { | 222 | static struct hda_pcm_stream ad198x_pcm_analog_capture = { |
184 | .substreams = 2, | 223 | .substreams = 1, |
185 | .channels_min = 2, | 224 | .channels_min = 2, |
186 | .channels_max = 2, | 225 | .channels_max = 2, |
187 | .nid = 0, /* fill later */ | 226 | .nid = 0, /* fill later */ |
@@ -202,6 +241,13 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = { | |||
202 | }, | 241 | }, |
203 | }; | 242 | }; |
204 | 243 | ||
244 | static struct hda_pcm_stream ad198x_pcm_digital_capture = { | ||
245 | .substreams = 1, | ||
246 | .channels_min = 2, | ||
247 | .channels_max = 2, | ||
248 | /* NID is set in alc_build_pcms */ | ||
249 | }; | ||
250 | |||
205 | static int ad198x_build_pcms(struct hda_codec *codec) | 251 | static int ad198x_build_pcms(struct hda_codec *codec) |
206 | { | 252 | { |
207 | struct ad198x_spec *spec = codec->spec; | 253 | struct ad198x_spec *spec = codec->spec; |
@@ -215,7 +261,8 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
215 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; | 261 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; |
216 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; | 262 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; |
217 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; | 263 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; |
218 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid; | 264 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; |
265 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
219 | 266 | ||
220 | if (spec->multiout.dig_out_nid) { | 267 | if (spec->multiout.dig_out_nid) { |
221 | info++; | 268 | info++; |
@@ -223,6 +270,10 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
223 | info->name = "AD198x Digital"; | 270 | info->name = "AD198x Digital"; |
224 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; | 271 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; |
225 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | 272 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; |
273 | if (spec->dig_in_nid) { | ||
274 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; | ||
275 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
276 | } | ||
226 | } | 277 | } |
227 | 278 | ||
228 | return 0; | 279 | return 0; |
@@ -237,10 +288,15 @@ static void ad198x_free(struct hda_codec *codec) | |||
237 | static int ad198x_resume(struct hda_codec *codec) | 288 | static int ad198x_resume(struct hda_codec *codec) |
238 | { | 289 | { |
239 | struct ad198x_spec *spec = codec->spec; | 290 | struct ad198x_spec *spec = codec->spec; |
291 | int i; | ||
240 | 292 | ||
241 | ad198x_init(codec); | 293 | ad198x_init(codec); |
242 | snd_hda_resume_ctls(codec, spec->mixers); | 294 | for (i = 0; i < spec->num_mixers; i++) |
243 | snd_hda_resume_spdif_out(codec); | 295 | snd_hda_resume_ctls(codec, spec->mixers[i]); |
296 | if (spec->multiout.dig_out_nid) | ||
297 | snd_hda_resume_spdif_out(codec); | ||
298 | if (spec->dig_in_nid) | ||
299 | snd_hda_resume_spdif_in(codec); | ||
244 | return 0; | 300 | return 0; |
245 | } | 301 | } |
246 | #endif | 302 | #endif |
@@ -269,6 +325,7 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
269 | static hda_nid_t ad1986a_dac_nids[3] = { | 325 | static hda_nid_t ad1986a_dac_nids[3] = { |
270 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC | 326 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC |
271 | }; | 327 | }; |
328 | static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; | ||
272 | 329 | ||
273 | static struct hda_input_mux ad1986a_capture_source = { | 330 | static struct hda_input_mux ad1986a_capture_source = { |
274 | .num_items = 7, | 331 | .num_items = 7, |
@@ -476,10 +533,13 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
476 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | 533 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); |
477 | spec->multiout.dac_nids = ad1986a_dac_nids; | 534 | spec->multiout.dac_nids = ad1986a_dac_nids; |
478 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | 535 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; |
479 | spec->adc_nid = AD1986A_ADC; | 536 | spec->num_adc_nids = 1; |
537 | spec->adc_nids = ad1986a_adc_nids; | ||
480 | spec->input_mux = &ad1986a_capture_source; | 538 | spec->input_mux = &ad1986a_capture_source; |
481 | spec->mixers = ad1986a_mixers; | 539 | spec->num_mixers = 1; |
482 | spec->init_verbs = ad1986a_init_verbs; | 540 | spec->mixers[0] = ad1986a_mixers; |
541 | spec->num_init_verbs = 1; | ||
542 | spec->init_verbs[0] = ad1986a_init_verbs; | ||
483 | 543 | ||
484 | codec->patch_ops = ad198x_patch_ops; | 544 | codec->patch_ops = ad198x_patch_ops; |
485 | 545 | ||
@@ -495,6 +555,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
495 | #define AD1983_ADC 0x04 | 555 | #define AD1983_ADC 0x04 |
496 | 556 | ||
497 | static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; | 557 | static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; |
558 | static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; | ||
498 | 559 | ||
499 | static struct hda_input_mux ad1983_capture_source = { | 560 | static struct hda_input_mux ad1983_capture_source = { |
500 | .num_items = 4, | 561 | .num_items = 4, |
@@ -619,6 +680,7 @@ static struct hda_verb ad1983_init_verbs[] = { | |||
619 | { } /* end */ | 680 | { } /* end */ |
620 | }; | 681 | }; |
621 | 682 | ||
683 | |||
622 | static int patch_ad1983(struct hda_codec *codec) | 684 | static int patch_ad1983(struct hda_codec *codec) |
623 | { | 685 | { |
624 | struct ad198x_spec *spec; | 686 | struct ad198x_spec *spec; |
@@ -634,10 +696,13 @@ static int patch_ad1983(struct hda_codec *codec) | |||
634 | spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); | 696 | spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); |
635 | spec->multiout.dac_nids = ad1983_dac_nids; | 697 | spec->multiout.dac_nids = ad1983_dac_nids; |
636 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; | 698 | spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; |
637 | spec->adc_nid = AD1983_ADC; | 699 | spec->num_adc_nids = 1; |
700 | spec->adc_nids = ad1983_adc_nids; | ||
638 | spec->input_mux = &ad1983_capture_source; | 701 | spec->input_mux = &ad1983_capture_source; |
639 | spec->mixers = ad1983_mixers; | 702 | spec->num_mixers = 1; |
640 | spec->init_verbs = ad1983_init_verbs; | 703 | spec->mixers[0] = ad1983_mixers; |
704 | spec->num_init_verbs = 1; | ||
705 | spec->init_verbs[0] = ad1983_init_verbs; | ||
641 | spec->spdif_route = 0; | 706 | spec->spdif_route = 0; |
642 | 707 | ||
643 | codec->patch_ops = ad198x_patch_ops; | 708 | codec->patch_ops = ad198x_patch_ops; |
@@ -655,6 +720,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
655 | #define AD1981_ADC 0x04 | 720 | #define AD1981_ADC 0x04 |
656 | 721 | ||
657 | static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; | 722 | static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; |
723 | static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; | ||
658 | 724 | ||
659 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ | 725 | /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ |
660 | static struct hda_input_mux ad1981_capture_source = { | 726 | static struct hda_input_mux ad1981_capture_source = { |
@@ -775,10 +841,13 @@ static int patch_ad1981(struct hda_codec *codec) | |||
775 | spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); | 841 | spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); |
776 | spec->multiout.dac_nids = ad1981_dac_nids; | 842 | spec->multiout.dac_nids = ad1981_dac_nids; |
777 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; | 843 | spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; |
778 | spec->adc_nid = AD1981_ADC; | 844 | spec->num_adc_nids = 1; |
845 | spec->adc_nids = ad1981_adc_nids; | ||
779 | spec->input_mux = &ad1981_capture_source; | 846 | spec->input_mux = &ad1981_capture_source; |
780 | spec->mixers = ad1981_mixers; | 847 | spec->num_mixers = 1; |
781 | spec->init_verbs = ad1981_init_verbs; | 848 | spec->mixers[0] = ad1981_mixers; |
849 | spec->num_init_verbs = 1; | ||
850 | spec->init_verbs[0] = ad1981_init_verbs; | ||
782 | spec->spdif_route = 0; | 851 | spec->spdif_route = 0; |
783 | 852 | ||
784 | codec->patch_ops = ad198x_patch_ops; | 853 | codec->patch_ops = ad198x_patch_ops; |