diff options
author | Matt Porter <mporter@embeddedalley.com> | 2006-01-23 09:27:49 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-02-01 07:09:17 -0500 |
commit | 3cc08dc6ea677ed4e843120aa070e145b6781a4b (patch) | |
tree | e3ea5a742e92d1105e147e4429b1b26591e1a2eb /sound/pci | |
parent | d62c40e04cfcec3cef8093bd79d72fe86c8f2195 (diff) |
[ALSA] hda-codec - add sigmatel 927x codec support
Modules: HDA Codec driver
Adds support for the SigmaTel STAC927x HDA codec family.
Signed-off-by: Matt Porter <mporter@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 149 |
1 files changed, 142 insertions, 7 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f2f9465d4df2..d5342d20bd81 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -50,10 +50,11 @@ struct sigmatel_spec { | |||
50 | unsigned int surr_switch: 1; | 50 | unsigned int surr_switch: 1; |
51 | unsigned int line_switch: 1; | 51 | unsigned int line_switch: 1; |
52 | unsigned int mic_switch: 1; | 52 | unsigned int mic_switch: 1; |
53 | unsigned int alt_switch: 1; | ||
53 | 54 | ||
54 | /* playback */ | 55 | /* playback */ |
55 | struct hda_multi_out multiout; | 56 | struct hda_multi_out multiout; |
56 | hda_nid_t dac_nids[4]; | 57 | hda_nid_t dac_nids[5]; |
57 | 58 | ||
58 | /* capture */ | 59 | /* capture */ |
59 | hda_nid_t *adc_nids; | 60 | hda_nid_t *adc_nids; |
@@ -73,7 +74,7 @@ struct sigmatel_spec { | |||
73 | 74 | ||
74 | /* capture source */ | 75 | /* capture source */ |
75 | struct hda_input_mux *input_mux; | 76 | struct hda_input_mux *input_mux; |
76 | unsigned int cur_mux[2]; | 77 | unsigned int cur_mux[3]; |
77 | 78 | ||
78 | /* i/o switches */ | 79 | /* i/o switches */ |
79 | unsigned int io_switch[2]; | 80 | unsigned int io_switch[2]; |
@@ -107,6 +108,14 @@ static hda_nid_t stac922x_mux_nids[2] = { | |||
107 | 0x12, 0x13, | 108 | 0x12, 0x13, |
108 | }; | 109 | }; |
109 | 110 | ||
111 | static hda_nid_t stac927x_adc_nids[3] = { | ||
112 | 0x07, 0x08, 0x09 | ||
113 | }; | ||
114 | |||
115 | static hda_nid_t stac927x_mux_nids[3] = { | ||
116 | 0x15, 0x16, 0x17 | ||
117 | }; | ||
118 | |||
110 | static hda_nid_t stac9200_pin_nids[8] = { | 119 | static hda_nid_t stac9200_pin_nids[8] = { |
111 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, | 120 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, |
112 | }; | 121 | }; |
@@ -116,6 +125,12 @@ static hda_nid_t stac922x_pin_nids[10] = { | |||
116 | 0x0f, 0x10, 0x11, 0x15, 0x1b, | 125 | 0x0f, 0x10, 0x11, 0x15, 0x1b, |
117 | }; | 126 | }; |
118 | 127 | ||
128 | static hda_nid_t stac927x_pin_nids[14] = { | ||
129 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
130 | 0x0f, 0x10, 0x11, 0x12, 0x13, | ||
131 | 0x14, 0x21, 0x22, 0x23, | ||
132 | }; | ||
133 | |||
119 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 134 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
120 | { | 135 | { |
121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 136 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -155,6 +170,12 @@ static struct hda_verb stac922x_core_init[] = { | |||
155 | {} | 170 | {} |
156 | }; | 171 | }; |
157 | 172 | ||
173 | static struct hda_verb stac927x_core_init[] = { | ||
174 | /* set master volume and direct control */ | ||
175 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
176 | {} | ||
177 | }; | ||
178 | |||
158 | static struct snd_kcontrol_new stac9200_mixer[] = { | 179 | static struct snd_kcontrol_new stac9200_mixer[] = { |
159 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | 180 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
160 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | 181 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
@@ -188,6 +209,21 @@ static struct snd_kcontrol_new stac922x_mixer[] = { | |||
188 | { } /* end */ | 209 | { } /* end */ |
189 | }; | 210 | }; |
190 | 211 | ||
212 | static snd_kcontrol_new_t stac927x_mixer[] = { | ||
213 | { | ||
214 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
215 | .name = "Input Source", | ||
216 | .count = 1, | ||
217 | .info = stac92xx_mux_enum_info, | ||
218 | .get = stac92xx_mux_enum_get, | ||
219 | .put = stac92xx_mux_enum_put, | ||
220 | }, | ||
221 | HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
222 | HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), | ||
223 | HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
224 | { } /* end */ | ||
225 | }; | ||
226 | |||
191 | static int stac92xx_build_controls(struct hda_codec *codec) | 227 | static int stac92xx_build_controls(struct hda_codec *codec) |
192 | { | 228 | { |
193 | struct sigmatel_spec *spec = codec->spec; | 229 | struct sigmatel_spec *spec = codec->spec; |
@@ -281,6 +317,25 @@ static struct hda_board_config stac922x_cfg_tbl[] = { | |||
281 | {} /* terminator */ | 317 | {} /* terminator */ |
282 | }; | 318 | }; |
283 | 319 | ||
320 | static unsigned int ref927x_pin_configs[14] = { | ||
321 | 0x01813122, 0x01a19021, 0x01014010, 0x01016011, | ||
322 | 0x01012012, 0x01011014, 0x40000100, 0x40000100, | ||
323 | 0x40000100, 0x40000100, 0x40000100, 0x01441030, | ||
324 | 0x01c41030, 0x40000100, | ||
325 | }; | ||
326 | |||
327 | static unsigned int *stac927x_brd_tbl[] = { | ||
328 | ref927x_pin_configs, | ||
329 | }; | ||
330 | |||
331 | static struct hda_board_config stac927x_cfg_tbl[] = { | ||
332 | { .modelname = "ref", | ||
333 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
334 | .pci_subdevice = 0x2668, /* DFI LanParty */ | ||
335 | .config = STAC_REF }, /* SigmaTel reference board */ | ||
336 | {} /* terminator */ | ||
337 | }; | ||
338 | |||
284 | static void stac92xx_set_config_regs(struct hda_codec *codec) | 339 | static void stac92xx_set_config_regs(struct hda_codec *codec) |
285 | { | 340 | { |
286 | int i; | 341 | int i; |
@@ -412,11 +467,23 @@ static struct hda_pcm_stream stac92xx_pcm_analog_playback = { | |||
412 | }, | 467 | }, |
413 | }; | 468 | }; |
414 | 469 | ||
470 | static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { | ||
471 | .substreams = 1, | ||
472 | .channels_min = 2, | ||
473 | .channels_max = 2, | ||
474 | .nid = 0x06, /* NID to query formats and rates */ | ||
475 | .ops = { | ||
476 | .open = stac92xx_playback_pcm_open, | ||
477 | .prepare = stac92xx_playback_pcm_prepare, | ||
478 | .cleanup = stac92xx_playback_pcm_cleanup | ||
479 | }, | ||
480 | }; | ||
481 | |||
415 | static struct hda_pcm_stream stac92xx_pcm_analog_capture = { | 482 | static struct hda_pcm_stream stac92xx_pcm_analog_capture = { |
416 | .substreams = 2, | 483 | .substreams = 2, |
417 | .channels_min = 2, | 484 | .channels_min = 2, |
418 | .channels_max = 2, | 485 | .channels_max = 2, |
419 | .nid = 0x06, /* NID to query formats and rates */ | 486 | /* NID is set in stac92xx_build_pcms */ |
420 | .ops = { | 487 | .ops = { |
421 | .prepare = stac92xx_capture_pcm_prepare, | 488 | .prepare = stac92xx_capture_pcm_prepare, |
422 | .cleanup = stac92xx_capture_pcm_cleanup | 489 | .cleanup = stac92xx_capture_pcm_cleanup |
@@ -434,6 +501,14 @@ static int stac92xx_build_pcms(struct hda_codec *codec) | |||
434 | info->name = "STAC92xx Analog"; | 501 | info->name = "STAC92xx Analog"; |
435 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; | 502 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; |
436 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; | 503 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; |
504 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | ||
505 | |||
506 | if (spec->alt_switch) { | ||
507 | codec->num_pcms++; | ||
508 | info++; | ||
509 | info->name = "STAC92xx Analog Alt"; | ||
510 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback; | ||
511 | } | ||
437 | 512 | ||
438 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | 513 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { |
439 | codec->num_pcms++; | 514 | codec->num_pcms++; |
@@ -592,6 +667,16 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf | |||
592 | return 0; | 667 | return 0; |
593 | } | 668 | } |
594 | 669 | ||
670 | /* | ||
671 | * XXX The line_out pin widget connection list may not be set to the | ||
672 | * desired DAC nid. This is the case on 927x where ports A and B can | ||
673 | * be routed to several DACs. | ||
674 | * | ||
675 | * This requires an analysis of the line-out/hp pin configuration | ||
676 | * to provide a best fit for pin/DAC configurations that are routable. | ||
677 | * For now, 927x DAC4 is not supported and 927x DAC1 output to ports | ||
678 | * A and B is not supported. | ||
679 | */ | ||
595 | /* fill in the dac_nids table from the parsed pin configuration */ | 680 | /* fill in the dac_nids table from the parsed pin configuration */ |
596 | static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) | 681 | static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) |
597 | { | 682 | { |
@@ -757,7 +842,7 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec) | |||
757 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 842 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); |
758 | } | 843 | } |
759 | 844 | ||
760 | static int stac922x_parse_auto_config(struct hda_codec *codec) | 845 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) |
761 | { | 846 | { |
762 | struct sigmatel_spec *spec = codec->spec; | 847 | struct sigmatel_spec *spec = codec->spec; |
763 | int err; | 848 | int err; |
@@ -781,11 +866,11 @@ static int stac922x_parse_auto_config(struct hda_codec *codec) | |||
781 | spec->surr_switch = 1; | 866 | spec->surr_switch = 1; |
782 | 867 | ||
783 | if (spec->autocfg.dig_out_pin) { | 868 | if (spec->autocfg.dig_out_pin) { |
784 | spec->multiout.dig_out_nid = 0x08; | 869 | spec->multiout.dig_out_nid = dig_out; |
785 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); | 870 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN); |
786 | } | 871 | } |
787 | if (spec->autocfg.dig_in_pin) { | 872 | if (spec->autocfg.dig_in_pin) { |
788 | spec->dig_in_nid = 0x09; | 873 | spec->dig_in_nid = dig_in; |
789 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN); | 874 | stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN); |
790 | } | 875 | } |
791 | 876 | ||
@@ -1000,7 +1085,47 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1000 | 1085 | ||
1001 | spec->multiout.dac_nids = spec->dac_nids; | 1086 | spec->multiout.dac_nids = spec->dac_nids; |
1002 | 1087 | ||
1003 | err = stac922x_parse_auto_config(codec); | 1088 | err = stac92xx_parse_auto_config(codec, 0x08, 0x09); |
1089 | if (err < 0) { | ||
1090 | stac92xx_free(codec); | ||
1091 | return err; | ||
1092 | } | ||
1093 | |||
1094 | codec->patch_ops = stac92xx_patch_ops; | ||
1095 | |||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | static int patch_stac927x(struct hda_codec *codec) | ||
1100 | { | ||
1101 | struct sigmatel_spec *spec; | ||
1102 | int err; | ||
1103 | |||
1104 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1105 | if (spec == NULL) | ||
1106 | return -ENOMEM; | ||
1107 | |||
1108 | codec->spec = spec; | ||
1109 | spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); | ||
1110 | if (spec->board_config < 0) | ||
1111 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); | ||
1112 | else { | ||
1113 | spec->num_pins = 14; | ||
1114 | spec->pin_nids = stac927x_pin_nids; | ||
1115 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; | ||
1116 | stac92xx_set_config_regs(codec); | ||
1117 | } | ||
1118 | |||
1119 | spec->adc_nids = stac927x_adc_nids; | ||
1120 | spec->mux_nids = stac927x_mux_nids; | ||
1121 | spec->num_muxes = 3; | ||
1122 | |||
1123 | spec->init = stac927x_core_init; | ||
1124 | spec->mixer = stac927x_mixer; | ||
1125 | |||
1126 | spec->multiout.dac_nids = spec->dac_nids; | ||
1127 | |||
1128 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | ||
1004 | if (err < 0) { | 1129 | if (err < 0) { |
1005 | stac92xx_free(codec); | 1130 | stac92xx_free(codec); |
1006 | return err; | 1131 | return err; |
@@ -1022,5 +1147,15 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
1022 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, | 1147 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, |
1023 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, | 1148 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, |
1024 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, | 1149 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, |
1150 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, | ||
1151 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, | ||
1152 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, | ||
1153 | { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x }, | ||
1154 | { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x }, | ||
1155 | { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x }, | ||
1156 | { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x }, | ||
1157 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, | ||
1158 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, | ||
1159 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, | ||
1025 | {} /* terminator */ | 1160 | {} /* terminator */ |
1026 | }; | 1161 | }; |