diff options
author | Matt <matt@embeddedalley.com> | 2005-06-14 04:19:34 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 06:29:05 -0400 |
commit | dabbed6f729d806092851150ca3dd9efe2b64b58 (patch) | |
tree | c6b6acdacb9f4cf67b3eeadf55225226a9171098 /sound | |
parent | ee3b4c60f452f8e24fe30ae73cb97da1beda0ca2 (diff) |
[ALSA] SigmaTel HDA SPDIF and input mux updates
HDA Codec driver
Adds SPDIF in/out support to the SigmaTel HDA codecs. Now builds
the input mux control element names from the defcfg regs.
Signed-off-by: Matt <matt@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 184 |
1 files changed, 145 insertions, 39 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1534e20af63d..013be2ea513a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -42,9 +42,11 @@ struct sigmatel_spec { | |||
42 | 42 | ||
43 | /* capture */ | 43 | /* capture */ |
44 | hda_nid_t *adc_nids; | 44 | hda_nid_t *adc_nids; |
45 | hda_nid_t *mux_nids; | ||
46 | unsigned int num_adcs; | 45 | unsigned int num_adcs; |
46 | hda_nid_t *mux_nids; | ||
47 | unsigned int num_muxes; | ||
47 | hda_nid_t capture_nid; | 48 | hda_nid_t capture_nid; |
49 | hda_nid_t dig_in_nid; | ||
48 | 50 | ||
49 | /* power management*/ | 51 | /* power management*/ |
50 | hda_nid_t *pstate_nids; | 52 | hda_nid_t *pstate_nids; |
@@ -62,7 +64,8 @@ struct sigmatel_spec { | |||
62 | snd_kcontrol_new_t *mixer; | 64 | snd_kcontrol_new_t *mixer; |
63 | 65 | ||
64 | /* capture source */ | 66 | /* capture source */ |
65 | const struct hda_input_mux *input_mux; | 67 | struct hda_input_mux input_mux; |
68 | char input_labels[HDA_MAX_NUM_INPUTS][16]; | ||
66 | unsigned int cur_mux[2]; | 69 | unsigned int cur_mux[2]; |
67 | 70 | ||
68 | /* channel mode */ | 71 | /* channel mode */ |
@@ -105,8 +108,8 @@ static hda_nid_t stac922x_dac_nids[4] = { | |||
105 | 0x02, 0x03, 0x04, 0x05, | 108 | 0x02, 0x03, 0x04, 0x05, |
106 | }; | 109 | }; |
107 | 110 | ||
108 | static hda_nid_t stac922x_pstate_nids[7] = { | 111 | static hda_nid_t stac922x_pstate_nids[8] = { |
109 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | 112 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, |
110 | }; | 113 | }; |
111 | 114 | ||
112 | static hda_nid_t stac922x_pin_nids[10] = { | 115 | static hda_nid_t stac922x_pin_nids[10] = { |
@@ -118,7 +121,7 @@ static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t | |||
118 | { | 121 | { |
119 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 122 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
120 | struct sigmatel_spec *spec = codec->spec; | 123 | struct sigmatel_spec *spec = codec->spec; |
121 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | 124 | return snd_hda_input_mux_info(&spec->input_mux, uinfo); |
122 | } | 125 | } |
123 | 126 | ||
124 | static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | 127 | static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) |
@@ -137,7 +140,7 @@ static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t | |||
137 | struct sigmatel_spec *spec = codec->spec; | 140 | struct sigmatel_spec *spec = codec->spec; |
138 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 141 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
139 | 142 | ||
140 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 143 | return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, |
141 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); | 144 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); |
142 | } | 145 | } |
143 | 146 | ||
@@ -192,30 +195,6 @@ static snd_kcontrol_new_t stac922x_mixer[] = { | |||
192 | { } /* end */ | 195 | { } /* end */ |
193 | }; | 196 | }; |
194 | 197 | ||
195 | static struct hda_input_mux stac9200_input_mux = { | ||
196 | .num_items = 5, | ||
197 | .items = { | ||
198 | { "Port B", 0x0 }, | ||
199 | { "Port C", 0x1 }, | ||
200 | { "Port D", 0x2 }, | ||
201 | { "Port A", 0x3 }, | ||
202 | { "CD", 0x4 }, | ||
203 | } | ||
204 | }; | ||
205 | |||
206 | static struct hda_input_mux stac922x_input_mux = { | ||
207 | .num_items = 7, | ||
208 | .items = { | ||
209 | { "Port E", 0x0 }, | ||
210 | { "CD", 0x1 }, | ||
211 | { "Port F", 0x2 }, | ||
212 | { "Port B", 0x3 }, | ||
213 | { "Port C", 0x4 }, | ||
214 | { "Port D", 0x5 }, | ||
215 | { "Port A", 0x6 }, | ||
216 | } | ||
217 | }; | ||
218 | |||
219 | static int stac92xx_build_controls(struct hda_codec *codec) | 198 | static int stac92xx_build_controls(struct hda_codec *codec) |
220 | { | 199 | { |
221 | struct sigmatel_spec *spec = codec->spec; | 200 | struct sigmatel_spec *spec = codec->spec; |
@@ -224,19 +203,28 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
224 | err = snd_hda_add_new_ctls(codec, spec->mixer); | 203 | err = snd_hda_add_new_ctls(codec, spec->mixer); |
225 | if (err < 0) | 204 | if (err < 0) |
226 | return err; | 205 | return err; |
227 | 206 | if (spec->multiout.dig_out_nid) { | |
228 | return 0; | 207 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); |
208 | if (err < 0) | ||
209 | return err; | ||
210 | } | ||
211 | if (spec->dig_in_nid) { | ||
212 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
213 | if (err < 0) | ||
214 | return err; | ||
215 | } | ||
216 | return 0; | ||
229 | } | 217 | } |
230 | 218 | ||
231 | #ifdef STAC_TEST | 219 | #ifdef STAC_TEST |
232 | static unsigned int stac9200_pin_configs[8] = { | 220 | static unsigned int stac9200_pin_configs[8] = { |
233 | 0x40000100, 0x40000100, 0x0221401f, 0x01114010, | 221 | 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, |
234 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, | 222 | 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, |
235 | }; | 223 | }; |
236 | 224 | ||
237 | static unsigned int stac922x_pin_configs[14] = { | 225 | static unsigned int stac922x_pin_configs[14] = { |
238 | 0x40000100, 0x40000100, 0x40000100, 0x01114010, | 226 | 0x40000100, 0x40000100, 0x40000100, 0x01114010, |
239 | 0x01813122, 0x40000100, 0x40000100, 0x40000100, | 227 | 0x01813122, 0x40000100, 0x01447010, 0x01c47010, |
240 | 0x40000100, 0x40000100, | 228 | 0x40000100, 0x40000100, |
241 | }; | 229 | }; |
242 | 230 | ||
@@ -299,29 +287,89 @@ static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid) | |||
299 | return 0; | 287 | return 0; |
300 | } | 288 | } |
301 | 289 | ||
290 | /* | ||
291 | * retrieve the default device type from the default config value | ||
292 | */ | ||
293 | #define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | ||
294 | #define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | ||
295 | |||
302 | static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) | 296 | static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg) |
303 | { | 297 | { |
304 | switch((pin_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) { | 298 | struct sigmatel_spec *spec = codec->spec; |
299 | u32 location = get_defcfg_location(pin_cfg); | ||
300 | char *label; | ||
301 | const char *type = NULL; | ||
302 | int ainput = 0; | ||
303 | |||
304 | switch(get_defcfg_type(pin_cfg)) { | ||
305 | case AC_JACK_HP_OUT: | 305 | case AC_JACK_HP_OUT: |
306 | /* Enable HP amp */ | 306 | /* Enable HP amp */ |
307 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); | 307 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN); |
308 | /* Fall through */ | 308 | /* Fall through */ |
309 | case AC_JACK_SPDIF_OUT: | ||
309 | case AC_JACK_LINE_OUT: | 310 | case AC_JACK_LINE_OUT: |
310 | case AC_JACK_SPEAKER: | 311 | case AC_JACK_SPEAKER: |
311 | /* Enable output */ | 312 | /* Enable output */ |
312 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); | 313 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); |
313 | break; | 314 | break; |
315 | case AC_JACK_SPDIF_IN: | ||
316 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
317 | break; | ||
314 | case AC_JACK_MIC_IN: | 318 | case AC_JACK_MIC_IN: |
319 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
320 | type = "Front Mic"; | ||
321 | else | ||
322 | type = "Mic"; | ||
323 | ainput = 1; | ||
315 | /* Set vref */ | 324 | /* Set vref */ |
316 | stac92xx_set_vref(codec, nid); | 325 | stac92xx_set_vref(codec, nid); |
326 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
327 | break; | ||
317 | case AC_JACK_CD: | 328 | case AC_JACK_CD: |
329 | type = "CD"; | ||
330 | ainput = 1; | ||
331 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
332 | break; | ||
318 | case AC_JACK_LINE_IN: | 333 | case AC_JACK_LINE_IN: |
334 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
335 | type = "Front Line"; | ||
336 | else | ||
337 | type = "Line"; | ||
338 | ainput = 1; | ||
339 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | ||
340 | break; | ||
319 | case AC_JACK_AUX: | 341 | case AC_JACK_AUX: |
320 | /* Enable input */ | 342 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
343 | type = "Front Aux"; | ||
344 | else | ||
345 | type = "Aux"; | ||
346 | ainput = 1; | ||
321 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); | 347 | stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN); |
322 | break; | 348 | break; |
323 | } | 349 | } |
324 | 350 | ||
351 | if (ainput) { | ||
352 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; | ||
353 | int i, j, num_cons, index = -1; | ||
354 | if (!type) | ||
355 | type = "Input"; | ||
356 | label = spec->input_labels[spec->input_mux.num_items]; | ||
357 | strcpy(label, type); | ||
358 | spec->input_mux.items[spec->input_mux.num_items].label = label; | ||
359 | for (i=0; i<spec->num_muxes; i++) { | ||
360 | num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS); | ||
361 | for (j=0; j<num_cons; j++) | ||
362 | if (con_lst[j] == nid) { | ||
363 | index = j; | ||
364 | break; | ||
365 | } | ||
366 | if (index >= 0) | ||
367 | break; | ||
368 | } | ||
369 | spec->input_mux.items[spec->input_mux.num_items].index = index; | ||
370 | spec->input_mux.num_items++; | ||
371 | } | ||
372 | |||
325 | return 0; | 373 | return 0; |
326 | } | 374 | } |
327 | 375 | ||
@@ -402,6 +450,26 @@ static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
402 | } | 450 | } |
403 | 451 | ||
404 | /* | 452 | /* |
453 | * Digital playback callbacks | ||
454 | */ | ||
455 | static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
456 | struct hda_codec *codec, | ||
457 | snd_pcm_substream_t *substream) | ||
458 | { | ||
459 | struct sigmatel_spec *spec = codec->spec; | ||
460 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
461 | } | ||
462 | |||
463 | static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
464 | struct hda_codec *codec, | ||
465 | snd_pcm_substream_t *substream) | ||
466 | { | ||
467 | struct sigmatel_spec *spec = codec->spec; | ||
468 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
469 | } | ||
470 | |||
471 | |||
472 | /* | ||
405 | * Analog capture callbacks | 473 | * Analog capture callbacks |
406 | */ | 474 | */ |
407 | static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | 475 | static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, |
@@ -427,6 +495,24 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
427 | return 0; | 495 | return 0; |
428 | } | 496 | } |
429 | 497 | ||
498 | static struct hda_pcm_stream stac92xx_pcm_digital_playback = { | ||
499 | .substreams = 1, | ||
500 | .channels_min = 2, | ||
501 | .channels_max = 2, | ||
502 | /* NID is set in stac92xx_build_pcms */ | ||
503 | .ops = { | ||
504 | .open = stac92xx_dig_playback_pcm_open, | ||
505 | .close = stac92xx_dig_playback_pcm_close | ||
506 | }, | ||
507 | }; | ||
508 | |||
509 | static struct hda_pcm_stream stac92xx_pcm_digital_capture = { | ||
510 | .substreams = 1, | ||
511 | .channels_min = 2, | ||
512 | .channels_max = 2, | ||
513 | /* NID is set in stac92xx_build_pcms */ | ||
514 | }; | ||
515 | |||
430 | static struct hda_pcm_stream stac92xx_pcm_analog_playback = { | 516 | static struct hda_pcm_stream stac92xx_pcm_analog_playback = { |
431 | .substreams = 1, | 517 | .substreams = 1, |
432 | .channels_min = 2, | 518 | .channels_min = 2, |
@@ -464,6 +550,20 @@ static int stac92xx_build_pcms(struct hda_codec *codec) | |||
464 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; | 550 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; |
465 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; | 551 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid; |
466 | 552 | ||
553 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | ||
554 | codec->num_pcms++; | ||
555 | info++; | ||
556 | info->name = "STAC92xx Digital"; | ||
557 | if (spec->multiout.dig_out_nid) { | ||
558 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; | ||
559 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
560 | } | ||
561 | if (spec->dig_in_nid) { | ||
562 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; | ||
563 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
564 | } | ||
565 | } | ||
566 | |||
467 | return 0; | 567 | return 0; |
468 | } | 568 | } |
469 | 569 | ||
@@ -492,9 +592,12 @@ static int patch_stac9200(struct hda_codec *codec) | |||
492 | spec->multiout.max_channels = 2; | 592 | spec->multiout.max_channels = 2; |
493 | spec->multiout.num_dacs = 1; | 593 | spec->multiout.num_dacs = 1; |
494 | spec->multiout.dac_nids = stac9200_dac_nids; | 594 | spec->multiout.dac_nids = stac9200_dac_nids; |
595 | spec->multiout.dig_out_nid = 0x05; | ||
596 | spec->dig_in_nid = 0x04; | ||
495 | spec->adc_nids = stac9200_adc_nids; | 597 | spec->adc_nids = stac9200_adc_nids; |
496 | spec->mux_nids = stac9200_mux_nids; | 598 | spec->mux_nids = stac9200_mux_nids; |
497 | spec->input_mux = &stac9200_input_mux; | 599 | spec->num_muxes = 1; |
600 | spec->input_mux.num_items = 0; | ||
498 | spec->pstate_nids = stac9200_pstate_nids; | 601 | spec->pstate_nids = stac9200_pstate_nids; |
499 | spec->num_pstates = 3; | 602 | spec->num_pstates = 3; |
500 | spec->pin_nids = stac9200_pin_nids; | 603 | spec->pin_nids = stac9200_pin_nids; |
@@ -525,11 +628,14 @@ static int patch_stac922x(struct hda_codec *codec) | |||
525 | spec->multiout.max_channels = 2; | 628 | spec->multiout.max_channels = 2; |
526 | spec->multiout.num_dacs = 4; | 629 | spec->multiout.num_dacs = 4; |
527 | spec->multiout.dac_nids = stac922x_dac_nids; | 630 | spec->multiout.dac_nids = stac922x_dac_nids; |
631 | spec->multiout.dig_out_nid = 0x08; | ||
632 | spec->dig_in_nid = 0x09; | ||
528 | spec->adc_nids = stac922x_adc_nids; | 633 | spec->adc_nids = stac922x_adc_nids; |
529 | spec->mux_nids = stac922x_mux_nids; | 634 | spec->mux_nids = stac922x_mux_nids; |
530 | spec->input_mux = &stac922x_input_mux; | 635 | spec->num_muxes = 2; |
636 | spec->input_mux.num_items = 0; | ||
531 | spec->pstate_nids = stac922x_pstate_nids; | 637 | spec->pstate_nids = stac922x_pstate_nids; |
532 | spec->num_pstates = 7; | 638 | spec->num_pstates = 8; |
533 | spec->pin_nids = stac922x_pin_nids; | 639 | spec->pin_nids = stac922x_pin_nids; |
534 | #ifdef STAC_TEST | 640 | #ifdef STAC_TEST |
535 | spec->pin_configs = stac922x_pin_configs; | 641 | spec->pin_configs = stac922x_pin_configs; |