blob: c94775c8a0bfad594c71be4a010fb2631eac7eed [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include <sound/driver.h>
28#include <linux/init.h>
29#include <linux/delay.h>
30#include <linux/slab.h>
31#include <linux/pci.h>
32#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020033#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020034#include "hda_codec.h"
35#include "hda_local.h"
36
Matt4e550962005-07-04 17:51:39 +020037#define NUM_CONTROL_ALLOC 32
38#define STAC_HP_EVENT 0x37
Matt4e550962005-07-04 17:51:39 +020039
Takashi Iwaif5fcc132006-11-24 17:07:44 +010040enum {
41 STAC_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020042 STAC_9200_DELL_D21,
43 STAC_9200_DELL_D22,
44 STAC_9200_DELL_D23,
45 STAC_9200_DELL_M21,
46 STAC_9200_DELL_M22,
47 STAC_9200_DELL_M23,
48 STAC_9200_DELL_M24,
49 STAC_9200_DELL_M25,
50 STAC_9200_DELL_M26,
51 STAC_9200_DELL_M27,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010052 STAC_9200_MODELS
53};
54
55enum {
56 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020057 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020058 STAC_9205_DELL_M43,
59 STAC_9205_DELL_M44,
60 STAC_9205_M43xx,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010061 STAC_9205_MODELS
62};
63
64enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010065 STAC_925x_REF,
66 STAC_M2_2,
67 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020068 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010069 STAC_925x_MODELS
70};
71
72enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010073 STAC_D945_REF,
74 STAC_D945GTP3,
75 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020076 STAC_INTEL_MAC_V1,
77 STAC_INTEL_MAC_V2,
78 STAC_INTEL_MAC_V3,
79 STAC_INTEL_MAC_V4,
80 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020081 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010082 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010083 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010084 STAC_MACBOOK_PRO_V1,
85 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +020086 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +020087 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020088 STAC_922X_DELL_D81,
89 STAC_922X_DELL_D82,
90 STAC_922X_DELL_M81,
91 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010092 STAC_922X_MODELS
93};
94
95enum {
96 STAC_D965_REF,
97 STAC_D965_3ST,
98 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +020099 STAC_DELL_3ST,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100100 STAC_927X_MODELS
101};
Matt Porter403d1942005-11-29 15:00:51 +0100102
Matt2f2f4252005-04-13 14:45:30 +0200103struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100104 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200105 unsigned int num_mixers;
106
Matt Porter403d1942005-11-29 15:00:51 +0100107 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200108 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100109 unsigned int line_switch: 1;
110 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100111 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100112 unsigned int hp_detect: 1;
Sam Revitch62fe78e2006-05-10 15:09:17 +0200113 unsigned int gpio_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200114
Takashi Iwai82599802007-07-31 15:56:24 +0200115 unsigned int gpio_mask, gpio_data;
116
Matt2f2f4252005-04-13 14:45:30 +0200117 /* playback */
118 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100119 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200120
121 /* capture */
122 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200123 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200124 hda_nid_t *mux_nids;
125 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200126 hda_nid_t *dmic_nids;
127 unsigned int num_dmics;
128 hda_nid_t dmux_nid;
Mattdabbed62005-06-14 10:19:34 +0200129 hda_nid_t dig_in_nid;
Matt2f2f4252005-04-13 14:45:30 +0200130
Matt2f2f4252005-04-13 14:45:30 +0200131 /* pin widgets */
132 hda_nid_t *pin_nids;
133 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200134 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200135 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200136
137 /* codec specific stuff */
138 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100139 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200140
141 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200142 struct hda_input_mux *dinput_mux;
143 unsigned int cur_dmux;
Mattc7d4b2f2005-06-27 14:59:41 +0200144 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100145 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200146
Matt Porter403d1942005-11-29 15:00:51 +0100147 /* i/o switches */
148 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200149 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200150 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200151
Mattc7d4b2f2005-06-27 14:59:41 +0200152 struct hda_pcm pcm_rec[2]; /* PCM information */
153
154 /* dynamic controls and input_mux */
155 struct auto_pin_cfg autocfg;
156 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100157 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200158 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200159 struct hda_input_mux private_imux;
Matt2f2f4252005-04-13 14:45:30 +0200160};
161
162static hda_nid_t stac9200_adc_nids[1] = {
163 0x03,
164};
165
166static hda_nid_t stac9200_mux_nids[1] = {
167 0x0c,
168};
169
170static hda_nid_t stac9200_dac_nids[1] = {
171 0x02,
172};
173
Tobin Davis8e21c342007-01-08 11:04:17 +0100174static hda_nid_t stac925x_adc_nids[1] = {
175 0x03,
176};
177
178static hda_nid_t stac925x_mux_nids[1] = {
179 0x0f,
180};
181
182static hda_nid_t stac925x_dac_nids[1] = {
183 0x02,
184};
185
Tobin Davis2c11f952007-05-17 09:36:34 +0200186static hda_nid_t stac925x_dmic_nids[1] = {
187 0x15,
188};
189
Matt2f2f4252005-04-13 14:45:30 +0200190static hda_nid_t stac922x_adc_nids[2] = {
191 0x06, 0x07,
192};
193
194static hda_nid_t stac922x_mux_nids[2] = {
195 0x12, 0x13,
196};
197
Matt Porter3cc08dc2006-01-23 15:27:49 +0100198static hda_nid_t stac927x_adc_nids[3] = {
199 0x07, 0x08, 0x09
200};
201
202static hda_nid_t stac927x_mux_nids[3] = {
203 0x15, 0x16, 0x17
204};
205
Matt Porterf3302a52006-07-31 12:49:34 +0200206static hda_nid_t stac9205_adc_nids[2] = {
207 0x12, 0x13
208};
209
210static hda_nid_t stac9205_mux_nids[2] = {
211 0x19, 0x1a
212};
213
Takashi Iwai25494132007-03-12 12:36:16 +0100214static hda_nid_t stac9205_dmic_nids[2] = {
215 0x17, 0x18,
Matt Porter8b657272006-10-26 17:12:59 +0200216};
217
Mattc7d4b2f2005-06-27 14:59:41 +0200218static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200219 0x08, 0x09, 0x0d, 0x0e,
220 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200221};
222
Tobin Davis8e21c342007-01-08 11:04:17 +0100223static hda_nid_t stac925x_pin_nids[8] = {
224 0x07, 0x08, 0x0a, 0x0b,
225 0x0c, 0x0d, 0x10, 0x11,
226};
227
Matt2f2f4252005-04-13 14:45:30 +0200228static hda_nid_t stac922x_pin_nids[10] = {
229 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
230 0x0f, 0x10, 0x11, 0x15, 0x1b,
231};
232
Matt Porter3cc08dc2006-01-23 15:27:49 +0100233static hda_nid_t stac927x_pin_nids[14] = {
234 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
235 0x0f, 0x10, 0x11, 0x12, 0x13,
236 0x14, 0x21, 0x22, 0x23,
237};
238
Matt Porterf3302a52006-07-31 12:49:34 +0200239static hda_nid_t stac9205_pin_nids[12] = {
240 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
241 0x0f, 0x14, 0x16, 0x17, 0x18,
242 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200243};
244
Matt Porter8b657272006-10-26 17:12:59 +0200245static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
246 struct snd_ctl_elem_info *uinfo)
247{
248 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
249 struct sigmatel_spec *spec = codec->spec;
250 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
251}
252
253static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
254 struct snd_ctl_elem_value *ucontrol)
255{
256 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
257 struct sigmatel_spec *spec = codec->spec;
258
259 ucontrol->value.enumerated.item[0] = spec->cur_dmux;
260 return 0;
261}
262
263static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
264 struct snd_ctl_elem_value *ucontrol)
265{
266 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
267 struct sigmatel_spec *spec = codec->spec;
268
269 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
270 spec->dmux_nid, &spec->cur_dmux);
271}
272
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100273static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200274{
275 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
276 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200277 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200278}
279
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100280static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200281{
282 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
283 struct sigmatel_spec *spec = codec->spec;
284 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
285
286 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
287 return 0;
288}
289
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100290static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200291{
292 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
293 struct sigmatel_spec *spec = codec->spec;
294 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
295
Mattc7d4b2f2005-06-27 14:59:41 +0200296 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200297 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
298}
299
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200300#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
301
302static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
303 struct snd_ctl_elem_value *ucontrol)
304{
305 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
306 struct sigmatel_spec *spec = codec->spec;
307
308 ucontrol->value.integer.value[0] = spec->aloopback;
309 return 0;
310}
311
312static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
313 struct snd_ctl_elem_value *ucontrol)
314{
315 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
316 struct sigmatel_spec *spec = codec->spec;
317 unsigned int dac_mode;
318
319 if (spec->aloopback == ucontrol->value.integer.value[0])
320 return 0;
321
322 spec->aloopback = ucontrol->value.integer.value[0];
323
324
325 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
326 kcontrol->private_value & 0xFFFF, 0x0);
327
328 if (spec->aloopback) {
329 snd_hda_power_up(codec);
330 dac_mode |= 0x40;
331 } else {
332 snd_hda_power_down(codec);
333 dac_mode &= ~0x40;
334 }
335
336 snd_hda_codec_write_cache(codec, codec->afg, 0,
337 kcontrol->private_value >> 16, dac_mode);
338
339 return 1;
340}
341
342
Mattc7d4b2f2005-06-27 14:59:41 +0200343static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200344 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200345 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200346 {}
347};
348
Tobin Davis8e21c342007-01-08 11:04:17 +0100349static struct hda_verb stac925x_core_init[] = {
350 /* set dac0mux for dac converter */
351 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
352 {}
353};
354
Mattc7d4b2f2005-06-27 14:59:41 +0200355static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200356 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200357 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200358 {}
359};
360
Tobin Davis93ed1502006-09-01 21:03:12 +0200361static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200362 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200363 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200364 /* unmute node 0x1b */
365 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
366 /* select node 0x03 as DAC */
367 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
368 {}
369};
370
Matt Porter3cc08dc2006-01-23 15:27:49 +0100371static struct hda_verb stac927x_core_init[] = {
372 /* set master volume and direct control */
373 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
374 {}
375};
376
Matt Porterf3302a52006-07-31 12:49:34 +0200377static struct hda_verb stac9205_core_init[] = {
378 /* set master volume and direct control */
379 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
380 {}
381};
382
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200383#define STAC_INPUT_SOURCE \
384 { \
385 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
386 .name = "Input Source", \
387 .count = 1, \
388 .info = stac92xx_mux_enum_info, \
389 .get = stac92xx_mux_enum_get, \
390 .put = stac92xx_mux_enum_put, \
391 }
392
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200393#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \
394 { \
395 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
396 .name = "Analog Loopback", \
397 .count = 1, \
398 .info = stac92xx_aloopback_info, \
399 .get = stac92xx_aloopback_get, \
400 .put = stac92xx_aloopback_put, \
401 .private_value = verb_read | (verb_write << 16), \
402 }
403
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200404
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100405static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200406 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
407 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200408 STAC_INPUT_SOURCE,
Matt2f2f4252005-04-13 14:45:30 +0200409 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
410 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200411 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200412 { } /* end */
413};
414
Tobin Davis8e21c342007-01-08 11:04:17 +0100415static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200416 STAC_INPUT_SOURCE,
Tobin Davis8e21c342007-01-08 11:04:17 +0100417 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
418 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
419 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
420 { } /* end */
421};
422
Mattc7d4b2f2005-06-27 14:59:41 +0200423/* This needs to be generated dynamically based on sequence */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100424static struct snd_kcontrol_new stac922x_mixer[] = {
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200425 STAC_INPUT_SOURCE,
Matt2f2f4252005-04-13 14:45:30 +0200426 HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT),
Takashi Iwai0fd17082006-01-13 18:46:21 +0100427 HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT),
Matt2f2f4252005-04-13 14:45:30 +0200428 HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT),
429 { } /* end */
430};
431
Takashi Iwai19039bd2006-06-28 15:52:16 +0200432/* This needs to be generated dynamically based on sequence */
433static struct snd_kcontrol_new stac9227_mixer[] = {
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200434 STAC_INPUT_SOURCE,
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200435 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB),
Takashi Iwai19039bd2006-06-28 15:52:16 +0200436 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
437 HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT),
438 { } /* end */
439};
440
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100441static struct snd_kcontrol_new stac927x_mixer[] = {
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200442 STAC_INPUT_SOURCE,
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200443 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB),
Matt Porter3cc08dc2006-01-23 15:27:49 +0100444 HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT),
445 HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT),
446 HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT),
447 { } /* end */
448};
449
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100450static struct snd_kcontrol_new stac9205_mixer[] = {
Matt Porterf3302a52006-07-31 12:49:34 +0200451 {
452 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matt Porter8b657272006-10-26 17:12:59 +0200453 .name = "Digital Input Source",
454 .count = 1,
455 .info = stac92xx_dmux_enum_info,
456 .get = stac92xx_dmux_enum_get,
457 .put = stac92xx_dmux_enum_put,
458 },
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200459 STAC_INPUT_SOURCE,
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200460 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0),
Matt Porterf3302a52006-07-31 12:49:34 +0200461 HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT),
462 HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT),
463 HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT),
464 { } /* end */
465};
466
Matt2f2f4252005-04-13 14:45:30 +0200467static int stac92xx_build_controls(struct hda_codec *codec)
468{
469 struct sigmatel_spec *spec = codec->spec;
470 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200471 int i;
Matt2f2f4252005-04-13 14:45:30 +0200472
473 err = snd_hda_add_new_ctls(codec, spec->mixer);
474 if (err < 0)
475 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200476
477 for (i = 0; i < spec->num_mixers; i++) {
478 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
479 if (err < 0)
480 return err;
481 }
482
Mattdabbed62005-06-14 10:19:34 +0200483 if (spec->multiout.dig_out_nid) {
484 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
485 if (err < 0)
486 return err;
487 }
488 if (spec->dig_in_nid) {
489 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
490 if (err < 0)
491 return err;
492 }
493 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200494}
495
Matt Porter403d1942005-11-29 15:00:51 +0100496static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200497 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200498 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
499};
500
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200501/*
502 STAC 9200 pin configs for
503 102801A8
504 102801DE
505 102801E8
506*/
507static unsigned int dell9200_d21_pin_configs[8] = {
508 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140,
509 0x01813122, 0x02214030, 0x01014010, 0x02a19020,
510};
511
512/*
513 STAC 9200 pin configs for
514 102801C0
515 102801C1
516*/
517static unsigned int dell9200_d22_pin_configs[8] = {
518 0x400001f0, 0x400001f1, 0x02a19021, 0x90100140,
519 0x400001f2, 0x0221401f, 0x01014010, 0x01813020,
520};
521
522/*
523 STAC 9200 pin configs for
524 102801C4 (Dell Dimension E310)
525 102801C5
526 102801C7
527 102801D9
528 102801DA
529 102801E3
530*/
531static unsigned int dell9200_d23_pin_configs[8] = {
532 0x400001f0, 0x400001f1, 0x01a19021, 0x90100140,
533 0x400001f2, 0x0221401f, 0x01014010, 0x01813020,
534};
535
536
537/*
538 STAC 9200-32 pin configs for
539 102801B5 (Dell Inspiron 630m)
540 102801D8 (Dell Inspiron 640m)
541*/
542static unsigned int dell9200_m21_pin_configs[8] = {
543 0x40c003fa, 0x03441340, 0x03a11020, 0x401003fc,
544 0x403003fd, 0x0321121f, 0x0321121f, 0x408003fb,
545};
546
547/*
548 STAC 9200-32 pin configs for
549 102801C2 (Dell Latitude D620)
550 102801C8
551 102801CC (Dell Latitude D820)
552 102801D4
553 102801D6
554*/
555static unsigned int dell9200_m22_pin_configs[8] = {
556 0x40c003fa, 0x0144131f, 0x03A11020, 0x401003fb,
557 0x40f000fc, 0x0321121f, 0x90170310, 0x90a70321,
558};
559
560/*
561 STAC 9200-32 pin configs for
562 102801CE (Dell XPS M1710)
563 102801CF (Dell Precision M90)
564*/
565static unsigned int dell9200_m23_pin_configs[8] = {
566 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
567 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
568};
569
570/*
571 STAC 9200-32 pin configs for
572 102801C9
573 102801CA
574 102801CB (Dell Latitude 120L)
575 102801D3
576*/
577static unsigned int dell9200_m24_pin_configs[8] = {
578 0x40c003fa, 0x404003fb, 0x03a11020, 0x401003fd,
579 0x403003fe, 0x0321121f, 0x90170310, 0x408003fc,
580};
581
582/*
583 STAC 9200-32 pin configs for
584 102801BD (Dell Inspiron E1505n)
585 102801EE
586 102801EF
587*/
588static unsigned int dell9200_m25_pin_configs[8] = {
589 0x40c003fa, 0x01441340, 0x04a11020, 0x401003fc,
590 0x403003fd, 0x0421121f, 0x90170310, 0x408003fb,
591};
592
593/*
594 STAC 9200-32 pin configs for
595 102801F5 (Dell Inspiron 1501)
596 102801F6
597*/
598static unsigned int dell9200_m26_pin_configs[8] = {
599 0x40c003fa, 0x404003fb, 0x04a11020, 0x401003fd,
600 0x403003fe, 0x0421121f, 0x90170310, 0x408003fc,
601};
602
603/*
604 STAC 9200-32
605 102801CD (Dell Inspiron E1705/9400)
606*/
607static unsigned int dell9200_m27_pin_configs[8] = {
608 0x40c003fa, 0x01441340, 0x04a11020, 0x90170310,
609 0x40f003fc, 0x0421121f, 0x90170310, 0x408003fb,
610};
611
612
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100613static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
614 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200615 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
616 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
617 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
618 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
619 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
620 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
621 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
622 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
623 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
624 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +0100625};
626
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100627static const char *stac9200_models[STAC_9200_MODELS] = {
628 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200629 [STAC_9200_DELL_D21] = "dell-d21",
630 [STAC_9200_DELL_D22] = "dell-d22",
631 [STAC_9200_DELL_D23] = "dell-d23",
632 [STAC_9200_DELL_M21] = "dell-m21",
633 [STAC_9200_DELL_M22] = "dell-m22",
634 [STAC_9200_DELL_M23] = "dell-m23",
635 [STAC_9200_DELL_M24] = "dell-m24",
636 [STAC_9200_DELL_M25] = "dell-m25",
637 [STAC_9200_DELL_M26] = "dell-m26",
638 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100639};
640
641static struct snd_pci_quirk stac9200_cfg_tbl[] = {
642 /* SigmaTel reference board */
643 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
644 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +0100645 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
647 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200649 "Dell Inspiron 630m", STAC_9200_DELL_M21),
650 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
651 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
652 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
653 "unknown Dell", STAC_9200_DELL_D22),
654 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
655 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100656 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200657 "Dell Latitude D620", STAC_9200_DELL_M22),
658 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
659 "unknown Dell", STAC_9200_DELL_D23),
660 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
661 "unknown Dell", STAC_9200_DELL_D23),
662 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
663 "unknown Dell", STAC_9200_DELL_M22),
664 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
665 "unknown Dell", STAC_9200_DELL_M24),
666 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
667 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100668 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200669 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +0100670 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200671 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +0100672 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200673 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +0100674 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200675 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +0100676 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200677 "Dell Precision M90", STAC_9200_DELL_M23),
678 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
679 "unknown Dell", STAC_9200_DELL_M22),
680 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
681 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +0200682 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200683 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +0200684 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200685 "Dell Inspiron 640m", STAC_9200_DELL_M21),
686 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
687 "unknown Dell", STAC_9200_DELL_D23),
688 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
689 "unknown Dell", STAC_9200_DELL_D23),
690 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
691 "unknown Dell", STAC_9200_DELL_D21),
692 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
693 "unknown Dell", STAC_9200_DELL_D23),
694 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
695 "unknown Dell", STAC_9200_DELL_D21),
696 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
697 "unknown Dell", STAC_9200_DELL_M25),
698 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
699 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +0200700 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200701 "Dell Inspiron 1501", STAC_9200_DELL_M26),
702 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
703 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +0200704 /* Panasonic */
705 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
706
Matt Porter403d1942005-11-29 15:00:51 +0100707 {} /* terminator */
708};
709
Tobin Davis8e21c342007-01-08 11:04:17 +0100710static unsigned int ref925x_pin_configs[8] = {
711 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
712 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
713};
714
715static unsigned int stac925x_MA6_pin_configs[8] = {
716 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
717 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
718};
719
Tobin Davis2c11f952007-05-17 09:36:34 +0200720static unsigned int stac925x_PA6_pin_configs[8] = {
721 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
722 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
723};
724
Tobin Davis8e21c342007-01-08 11:04:17 +0100725static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +0200726 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
727 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +0100728};
729
730static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
731 [STAC_REF] = ref925x_pin_configs,
732 [STAC_M2_2] = stac925xM2_2_pin_configs,
733 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +0200734 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +0100735};
736
737static const char *stac925x_models[STAC_925x_MODELS] = {
738 [STAC_REF] = "ref",
739 [STAC_M2_2] = "m2-2",
740 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +0200741 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +0100742};
743
744static struct snd_pci_quirk stac925x_cfg_tbl[] = {
745 /* SigmaTel reference board */
746 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +0200747 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +0100748 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
749 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
750 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +0200751 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +0100752 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
753 {} /* terminator */
754};
755
Matt Porter403d1942005-11-29 15:00:51 +0100756static unsigned int ref922x_pin_configs[10] = {
757 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
758 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +0200759 0x40000100, 0x40000100,
760};
761
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200762/*
763 STAC 922X pin configs for
764 102801A7
765 102801AB
766 102801A9
767 102801D1
768 102801D2
769*/
770static unsigned int dell_922x_d81_pin_configs[10] = {
771 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
772 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
773 0x01813122, 0x400001f2,
774};
775
776/*
777 STAC 922X pin configs for
778 102801AC
779 102801D0
780*/
781static unsigned int dell_922x_d82_pin_configs[10] = {
782 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
783 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
784 0x01813122, 0x400001f1,
785};
786
787/*
788 STAC 922X pin configs for
789 102801BF
790*/
791static unsigned int dell_922x_m81_pin_configs[10] = {
792 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
793 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
794 0x40C003f1, 0x405003f0,
795};
796
797/*
798 STAC 9221 A1 pin configs for
799 102801D7 (Dell XPS M1210)
800*/
801static unsigned int dell_922x_m82_pin_configs[10] = {
802 0x0221121f, 0x408103ff, 0x02111212, 0x90100310,
803 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2,
804 0x508003f3, 0x405003f4,
805};
806
Matt Porter403d1942005-11-29 15:00:51 +0100807static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +0100808 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +0100809 0x40000100, 0x40000100, 0x40000100, 0x40000100,
810 0x02a19120, 0x40000100,
811};
812
813static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +0100814 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
815 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +0100816 0x02a19320, 0x40000100,
817};
818
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200819static unsigned int intel_mac_v1_pin_configs[10] = {
820 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
821 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100822 0x400000fc, 0x400000fb,
823};
824
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200825static unsigned int intel_mac_v2_pin_configs[10] = {
826 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
827 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200828 0x400000fc, 0x400000fb,
829};
830
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200831static unsigned int intel_mac_v3_pin_configs[10] = {
832 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
833 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
834 0x400000fc, 0x400000fb,
835};
836
837static unsigned int intel_mac_v4_pin_configs[10] = {
838 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
839 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
840 0x400000fc, 0x400000fb,
841};
842
843static unsigned int intel_mac_v5_pin_configs[10] = {
844 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
845 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
846 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200847};
848
Takashi Iwai76c08822007-06-19 12:17:42 +0200849
Takashi Iwai19039bd2006-06-28 15:52:16 +0200850static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100851 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +0200852 [STAC_D945GTP3] = d945gtp3_pin_configs,
853 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200854 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
855 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
856 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
857 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
858 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200859 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200860 [STAC_MACMINI] = intel_mac_v3_pin_configs,
861 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
862 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
863 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
864 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
865 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200866 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
867 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
868 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
869 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +0100870};
871
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100872static const char *stac922x_models[STAC_922X_MODELS] = {
873 [STAC_D945_REF] = "ref",
874 [STAC_D945GTP5] = "5stack",
875 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200876 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
877 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
878 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
879 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
880 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200881 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100882 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100883 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100884 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
885 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +0200886 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200887 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200888 [STAC_922X_DELL_D81] = "dell-d81",
889 [STAC_922X_DELL_D82] = "dell-d82",
890 [STAC_922X_DELL_M81] = "dell-m81",
891 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100892};
893
894static struct snd_pci_quirk stac922x_cfg_tbl[] = {
895 /* SigmaTel reference board */
896 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
897 "DFI LanParty", STAC_D945_REF),
898 /* Intel 945G based systems */
899 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
900 "Intel D945G", STAC_D945GTP3),
901 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
902 "Intel D945G", STAC_D945GTP3),
903 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
904 "Intel D945G", STAC_D945GTP3),
905 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
906 "Intel D945G", STAC_D945GTP3),
907 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
908 "Intel D945G", STAC_D945GTP3),
909 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
910 "Intel D945G", STAC_D945GTP3),
911 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
912 "Intel D945G", STAC_D945GTP3),
913 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
914 "Intel D945G", STAC_D945GTP3),
915 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
916 "Intel D945G", STAC_D945GTP3),
917 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
918 "Intel D945G", STAC_D945GTP3),
919 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
920 "Intel D945G", STAC_D945GTP3),
921 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
922 "Intel D945G", STAC_D945GTP3),
923 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
924 "Intel D945G", STAC_D945GTP3),
925 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
926 "Intel D945G", STAC_D945GTP3),
927 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
928 "Intel D945G", STAC_D945GTP3),
929 /* Intel D945G 5-stack systems */
930 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
931 "Intel D945G", STAC_D945GTP5),
932 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
933 "Intel D945G", STAC_D945GTP5),
934 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
935 "Intel D945G", STAC_D945GTP5),
936 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
937 "Intel D945G", STAC_D945GTP5),
938 /* Intel 945P based systems */
939 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
940 "Intel D945P", STAC_D945GTP3),
941 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
942 "Intel D945P", STAC_D945GTP3),
943 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
944 "Intel D945P", STAC_D945GTP3),
945 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
946 "Intel D945P", STAC_D945GTP3),
947 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
948 "Intel D945P", STAC_D945GTP3),
949 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
950 "Intel D945P", STAC_D945GTP5),
951 /* other systems */
952 /* Apple Mac Mini (early 2006) */
953 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200954 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200955 /* Dell systems */
956 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
957 "unknown Dell", STAC_922X_DELL_D81),
958 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
959 "unknown Dell", STAC_922X_DELL_D81),
960 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
961 "unknown Dell", STAC_922X_DELL_D81),
962 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
963 "unknown Dell", STAC_922X_DELL_D82),
964 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
965 "unknown Dell", STAC_922X_DELL_M81),
966 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
967 "unknown Dell", STAC_922X_DELL_D82),
968 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
969 "unknown Dell", STAC_922X_DELL_D81),
970 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
971 "unknown Dell", STAC_922X_DELL_D81),
972 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
973 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +0100974 {} /* terminator */
975};
976
Matt Porter3cc08dc2006-01-23 15:27:49 +0100977static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200978 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
979 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
980 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
981 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +0100982};
983
Tobin Davis93ed1502006-09-01 21:03:12 +0200984static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +0200985 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
986 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
987 0x40000100, 0x40000100, 0x40000100, 0x40000100,
988 0x40000100, 0x40000100
989};
990
Tobin Davis93ed1502006-09-01 21:03:12 +0200991static unsigned int d965_5st_pin_configs[14] = {
992 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
993 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
994 0x40000100, 0x40000100, 0x40000100, 0x01442070,
995 0x40000100, 0x40000100
996};
997
Tobin Davis4ff076e2007-08-07 11:48:12 +0200998static unsigned int dell_3st_pin_configs[14] = {
999 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1000 0x01111212, 0x01116211, 0x01813050, 0x01112214,
1001 0x403003fa, 0x40000100, 0x40000100, 0x404003fb,
1002 0x40c003fc, 0x40000100
1003};
1004
Tobin Davis93ed1502006-09-01 21:03:12 +02001005static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001006 [STAC_D965_REF] = ref927x_pin_configs,
Tobin Davis93ed1502006-09-01 21:03:12 +02001007 [STAC_D965_3ST] = d965_3st_pin_configs,
1008 [STAC_D965_5ST] = d965_5st_pin_configs,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001009 [STAC_DELL_3ST] = dell_3st_pin_configs,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001010};
1011
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001012static const char *stac927x_models[STAC_927X_MODELS] = {
1013 [STAC_D965_REF] = "ref",
1014 [STAC_D965_3ST] = "3stack",
1015 [STAC_D965_5ST] = "5stack",
Tobin Davis4ff076e2007-08-07 11:48:12 +02001016 [STAC_DELL_3ST] = "dell-3stack",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001017};
1018
1019static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1020 /* SigmaTel reference board */
1021 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1022 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001023 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001024 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1025 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001026 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001027 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1028 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1029 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1030 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1031 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1032 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1033 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1034 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1035 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1036 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1037 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1038 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1039 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1040 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1041 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1042 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001043 /* Dell 3 stack systems */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001044 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001045 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1046 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001047 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001048 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1049 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1050 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1051 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1052 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1053 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1054 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1055 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1056 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001057 {} /* terminator */
1058};
1059
Matt Porterf3302a52006-07-31 12:49:34 +02001060static unsigned int ref9205_pin_configs[12] = {
1061 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matt Porter8b657272006-10-26 17:12:59 +02001062 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
1063 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001064};
1065
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001066/*
1067 STAC 9205 pin configs for
1068 102801F1
1069 102801F2
1070 102801FC
1071 102801FD
1072 10280204
1073 1028021F
1074*/
1075static unsigned int dell_9205_m42_pin_configs[12] = {
1076 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1077 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1078 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1079};
1080
1081/*
1082 STAC 9205 pin configs for
1083 102801F9
1084 102801FA
1085 102801FE
1086 102801FF (Dell Precision M4300)
1087 10280206
1088 10280200
1089 10280201
1090*/
1091static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001092 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1093 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1094 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1095};
1096
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001097static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001098 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1099 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1100 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1101};
1102
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001103static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001104 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001105 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1106 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1107 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001108 [STAC_9205_M43xx] = NULL,
Matt Porterf3302a52006-07-31 12:49:34 +02001109};
1110
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001111static const char *stac9205_models[STAC_9205_MODELS] = {
1112 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001113 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001114 [STAC_9205_DELL_M43] = "dell-m43",
1115 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001116};
1117
1118static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1119 /* SigmaTel reference board */
1120 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1121 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001122 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1123 "unknown Dell", STAC_9205_DELL_M42),
1124 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1125 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001126 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
1127 "Dell Precision", STAC_9205_M43xx),
1128 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1129 "Dell Precision", STAC_9205_DELL_M43),
1130 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1131 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001132 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1133 "unknown Dell", STAC_9205_DELL_M42),
1134 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1135 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1137 "Dell Precision", STAC_9205_DELL_M43),
1138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001139 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1141 "Dell Precision", STAC_9205_DELL_M43),
1142 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1143 "Dell Inspiron", STAC_9205_DELL_M44),
1144 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1145 "Dell Inspiron", STAC_9205_DELL_M44),
1146 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1147 "Dell Inspiron", STAC_9205_DELL_M44),
1148 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1149 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001150 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1151 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1153 "Dell Inspiron", STAC_9205_DELL_M44),
Matt Porterf3302a52006-07-31 12:49:34 +02001154 {} /* terminator */
1155};
1156
Richard Fish11b44bb2006-08-23 18:31:34 +02001157static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1158{
1159 int i;
1160 struct sigmatel_spec *spec = codec->spec;
1161
1162 if (! spec->bios_pin_configs) {
1163 spec->bios_pin_configs = kcalloc(spec->num_pins,
1164 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1165 if (! spec->bios_pin_configs)
1166 return -ENOMEM;
1167 }
1168
1169 for (i = 0; i < spec->num_pins; i++) {
1170 hda_nid_t nid = spec->pin_nids[i];
1171 unsigned int pin_cfg;
1172
1173 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1174 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1175 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1176 nid, pin_cfg);
1177 spec->bios_pin_configs[i] = pin_cfg;
1178 }
1179
1180 return 0;
1181}
1182
Matthew Ranostay87d48362007-07-17 11:52:24 +02001183static void stac92xx_set_config_reg(struct hda_codec *codec,
1184 hda_nid_t pin_nid, unsigned int pin_config)
1185{
1186 int i;
1187 snd_hda_codec_write(codec, pin_nid, 0,
1188 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1189 pin_config & 0x000000ff);
1190 snd_hda_codec_write(codec, pin_nid, 0,
1191 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1192 (pin_config & 0x0000ff00) >> 8);
1193 snd_hda_codec_write(codec, pin_nid, 0,
1194 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1195 (pin_config & 0x00ff0000) >> 16);
1196 snd_hda_codec_write(codec, pin_nid, 0,
1197 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1198 pin_config >> 24);
1199 i = snd_hda_codec_read(codec, pin_nid, 0,
1200 AC_VERB_GET_CONFIG_DEFAULT,
1201 0x00);
1202 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1203 pin_nid, i);
1204}
1205
Matt2f2f4252005-04-13 14:45:30 +02001206static void stac92xx_set_config_regs(struct hda_codec *codec)
1207{
1208 int i;
1209 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001210
Matthew Ranostay87d48362007-07-17 11:52:24 +02001211 if (!spec->pin_configs)
1212 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001213
Matthew Ranostay87d48362007-07-17 11:52:24 +02001214 for (i = 0; i < spec->num_pins; i++)
1215 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1216 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001217}
Matt2f2f4252005-04-13 14:45:30 +02001218
Takashi Iwai82599802007-07-31 15:56:24 +02001219static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
Matthew Ranostay92a22be2007-06-19 16:48:28 +02001220{
Takashi Iwai82599802007-07-31 15:56:24 +02001221 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay87d48362007-07-17 11:52:24 +02001222 /* Configure GPIOx as output */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001223 snd_hda_codec_write_cache(codec, codec->afg, 0,
1224 AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001225 /* Configure GPIOx as CMOS */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001226 snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001227 /* Assert GPIOx */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001228 snd_hda_codec_write_cache(codec, codec->afg, 0,
1229 AC_VERB_SET_GPIO_DATA, spec->gpio_data);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001230 /* Enable GPIOx */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001231 snd_hda_codec_write_cache(codec, codec->afg, 0,
1232 AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
Matthew Ranostay92a22be2007-06-19 16:48:28 +02001233}
1234
Matt2f2f4252005-04-13 14:45:30 +02001235/*
1236 * Analog playback callbacks
1237 */
1238static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1239 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001240 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001241{
1242 struct sigmatel_spec *spec = codec->spec;
1243 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1244}
1245
1246static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1247 struct hda_codec *codec,
1248 unsigned int stream_tag,
1249 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001250 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001251{
1252 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001253 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001254}
1255
1256static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1257 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001258 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001259{
1260 struct sigmatel_spec *spec = codec->spec;
1261 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1262}
1263
1264/*
Mattdabbed62005-06-14 10:19:34 +02001265 * Digital playback callbacks
1266 */
1267static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1268 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001269 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001270{
1271 struct sigmatel_spec *spec = codec->spec;
1272 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1273}
1274
1275static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1276 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001277 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001278{
1279 struct sigmatel_spec *spec = codec->spec;
1280 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1281}
1282
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001283static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1284 struct hda_codec *codec,
1285 unsigned int stream_tag,
1286 unsigned int format,
1287 struct snd_pcm_substream *substream)
1288{
1289 struct sigmatel_spec *spec = codec->spec;
1290 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1291 stream_tag, format, substream);
1292}
1293
Mattdabbed62005-06-14 10:19:34 +02001294
1295/*
Matt2f2f4252005-04-13 14:45:30 +02001296 * Analog capture callbacks
1297 */
1298static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1299 struct hda_codec *codec,
1300 unsigned int stream_tag,
1301 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001302 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001303{
1304 struct sigmatel_spec *spec = codec->spec;
1305
1306 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1307 stream_tag, 0, format);
1308 return 0;
1309}
1310
1311static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1312 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001313 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001314{
1315 struct sigmatel_spec *spec = codec->spec;
1316
1317 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1318 return 0;
1319}
1320
Mattdabbed62005-06-14 10:19:34 +02001321static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1322 .substreams = 1,
1323 .channels_min = 2,
1324 .channels_max = 2,
1325 /* NID is set in stac92xx_build_pcms */
1326 .ops = {
1327 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001328 .close = stac92xx_dig_playback_pcm_close,
1329 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001330 },
1331};
1332
1333static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1334 .substreams = 1,
1335 .channels_min = 2,
1336 .channels_max = 2,
1337 /* NID is set in stac92xx_build_pcms */
1338};
1339
Matt2f2f4252005-04-13 14:45:30 +02001340static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1341 .substreams = 1,
1342 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001343 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001344 .nid = 0x02, /* NID to query formats and rates */
1345 .ops = {
1346 .open = stac92xx_playback_pcm_open,
1347 .prepare = stac92xx_playback_pcm_prepare,
1348 .cleanup = stac92xx_playback_pcm_cleanup
1349 },
1350};
1351
Matt Porter3cc08dc2006-01-23 15:27:49 +01001352static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1353 .substreams = 1,
1354 .channels_min = 2,
1355 .channels_max = 2,
1356 .nid = 0x06, /* NID to query formats and rates */
1357 .ops = {
1358 .open = stac92xx_playback_pcm_open,
1359 .prepare = stac92xx_playback_pcm_prepare,
1360 .cleanup = stac92xx_playback_pcm_cleanup
1361 },
1362};
1363
Matt2f2f4252005-04-13 14:45:30 +02001364static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
1365 .substreams = 2,
1366 .channels_min = 2,
1367 .channels_max = 2,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001368 /* NID is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001369 .ops = {
1370 .prepare = stac92xx_capture_pcm_prepare,
1371 .cleanup = stac92xx_capture_pcm_cleanup
1372 },
1373};
1374
1375static int stac92xx_build_pcms(struct hda_codec *codec)
1376{
1377 struct sigmatel_spec *spec = codec->spec;
1378 struct hda_pcm *info = spec->pcm_rec;
1379
1380 codec->num_pcms = 1;
1381 codec->pcm_info = info;
1382
Mattc7d4b2f2005-06-27 14:59:41 +02001383 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001384 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001385 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001386 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1387
1388 if (spec->alt_switch) {
1389 codec->num_pcms++;
1390 info++;
1391 info->name = "STAC92xx Analog Alt";
1392 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1393 }
Matt2f2f4252005-04-13 14:45:30 +02001394
Mattdabbed62005-06-14 10:19:34 +02001395 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1396 codec->num_pcms++;
1397 info++;
1398 info->name = "STAC92xx Digital";
1399 if (spec->multiout.dig_out_nid) {
1400 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1401 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1402 }
1403 if (spec->dig_in_nid) {
1404 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1405 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1406 }
1407 }
1408
Matt2f2f4252005-04-13 14:45:30 +02001409 return 0;
1410}
1411
Takashi Iwaic960a032006-03-23 17:06:28 +01001412static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1413{
1414 unsigned int pincap = snd_hda_param_read(codec, nid,
1415 AC_PAR_PIN_CAP);
1416 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1417 if (pincap & AC_PINCAP_VREF_100)
1418 return AC_PINCTL_VREF_100;
1419 if (pincap & AC_PINCAP_VREF_80)
1420 return AC_PINCTL_VREF_80;
1421 if (pincap & AC_PINCAP_VREF_50)
1422 return AC_PINCTL_VREF_50;
1423 if (pincap & AC_PINCAP_VREF_GRD)
1424 return AC_PINCTL_VREF_GRD;
1425 return 0;
1426}
1427
Matt Porter403d1942005-11-29 15:00:51 +01001428static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1429
1430{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001431 snd_hda_codec_write_cache(codec, nid, 0,
1432 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001433}
1434
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001435#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001436
1437static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1438{
1439 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1440 struct sigmatel_spec *spec = codec->spec;
1441 int io_idx = kcontrol-> private_value & 0xff;
1442
1443 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1444 return 0;
1445}
1446
1447static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1448{
1449 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1450 struct sigmatel_spec *spec = codec->spec;
1451 hda_nid_t nid = kcontrol->private_value >> 8;
1452 int io_idx = kcontrol-> private_value & 0xff;
1453 unsigned short val = ucontrol->value.integer.value[0];
1454
1455 spec->io_switch[io_idx] = val;
1456
1457 if (val)
1458 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001459 else {
1460 unsigned int pinctl = AC_PINCTL_IN_EN;
1461 if (io_idx) /* set VREF for mic */
1462 pinctl |= stac92xx_get_vref(codec, nid);
1463 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1464 }
Matt Porter403d1942005-11-29 15:00:51 +01001465 return 1;
1466}
1467
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001468#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1469
1470static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1471 struct snd_ctl_elem_value *ucontrol)
1472{
1473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1474 struct sigmatel_spec *spec = codec->spec;
1475
1476 ucontrol->value.integer.value[0] = spec->clfe_swap;
1477 return 0;
1478}
1479
1480static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1481 struct snd_ctl_elem_value *ucontrol)
1482{
1483 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1484 struct sigmatel_spec *spec = codec->spec;
1485 hda_nid_t nid = kcontrol->private_value & 0xff;
1486
1487 if (spec->clfe_swap == ucontrol->value.integer.value[0])
1488 return 0;
1489
1490 spec->clfe_swap = ucontrol->value.integer.value[0];
1491
1492 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1493 spec->clfe_swap ? 0x4 : 0x0);
1494
1495 return 1;
1496}
1497
Matt Porter403d1942005-11-29 15:00:51 +01001498#define STAC_CODEC_IO_SWITCH(xname, xpval) \
1499 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1500 .name = xname, \
1501 .index = 0, \
1502 .info = stac92xx_io_switch_info, \
1503 .get = stac92xx_io_switch_get, \
1504 .put = stac92xx_io_switch_put, \
1505 .private_value = xpval, \
1506 }
1507
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001508#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
1509 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1510 .name = xname, \
1511 .index = 0, \
1512 .info = stac92xx_clfe_switch_info, \
1513 .get = stac92xx_clfe_switch_get, \
1514 .put = stac92xx_clfe_switch_put, \
1515 .private_value = xpval, \
1516 }
Matt Porter403d1942005-11-29 15:00:51 +01001517
Mattc7d4b2f2005-06-27 14:59:41 +02001518enum {
1519 STAC_CTL_WIDGET_VOL,
1520 STAC_CTL_WIDGET_MUTE,
Matt Porter403d1942005-11-29 15:00:51 +01001521 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001522 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02001523};
1524
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001525static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02001526 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
1527 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matt Porter403d1942005-11-29 15:00:51 +01001528 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001529 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02001530};
1531
1532/* add dynamic controls */
1533static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
1534{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001535 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02001536
1537 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
1538 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
1539
1540 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
1541 if (! knew)
1542 return -ENOMEM;
1543 if (spec->kctl_alloc) {
1544 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
1545 kfree(spec->kctl_alloc);
1546 }
1547 spec->kctl_alloc = knew;
1548 spec->num_kctl_alloc = num;
1549 }
1550
1551 knew = &spec->kctl_alloc[spec->num_kctl_used];
1552 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02001553 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02001554 if (! knew->name)
1555 return -ENOMEM;
1556 knew->private_value = val;
1557 spec->num_kctl_used++;
1558 return 0;
1559}
1560
Matt Porter403d1942005-11-29 15:00:51 +01001561/* flag inputs as additional dynamic lineouts */
1562static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
1563{
1564 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001565 unsigned int wcaps, wtype;
1566 int i, num_dacs = 0;
1567
1568 /* use the wcaps cache to count all DACs available for line-outs */
1569 for (i = 0; i < codec->num_nodes; i++) {
1570 wcaps = codec->wcaps[i];
1571 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
1572 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
1573 num_dacs++;
1574 }
Matt Porter403d1942005-11-29 15:00:51 +01001575
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001576 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
1577
Matt Porter403d1942005-11-29 15:00:51 +01001578 switch (cfg->line_outs) {
1579 case 3:
1580 /* add line-in as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001581 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001582 cfg->line_out_pins[cfg->line_outs] =
1583 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01001584 spec->line_switch = 1;
1585 cfg->line_outs++;
1586 }
1587 break;
1588 case 2:
1589 /* add line-in as clfe and mic as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001590 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001591 cfg->line_out_pins[cfg->line_outs] =
1592 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01001593 spec->line_switch = 1;
1594 cfg->line_outs++;
1595 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001596 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001597 cfg->line_out_pins[cfg->line_outs] =
1598 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01001599 spec->mic_switch = 1;
1600 cfg->line_outs++;
1601 }
1602 break;
1603 case 1:
1604 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001605 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001606 cfg->line_out_pins[cfg->line_outs] =
1607 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01001608 spec->line_switch = 1;
1609 cfg->line_outs++;
1610 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001611 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001612 cfg->line_out_pins[cfg->line_outs] =
1613 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01001614 spec->mic_switch = 1;
1615 cfg->line_outs++;
1616 }
1617 break;
1618 }
1619
1620 return 0;
1621}
1622
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001623
1624static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
1625{
1626 int i;
1627
1628 for (i = 0; i < spec->multiout.num_dacs; i++) {
1629 if (spec->multiout.dac_nids[i] == nid)
1630 return 1;
1631 }
1632
1633 return 0;
1634}
1635
Matt Porter3cc08dc2006-01-23 15:27:49 +01001636/*
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001637 * Fill in the dac_nids table from the parsed pin configuration
1638 * This function only works when every pin in line_out_pins[]
1639 * contains atleast one DAC in its connection list. Some 92xx
1640 * codecs are not connected directly to a DAC, such as the 9200
1641 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01001642 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02001643static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02001644 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02001645{
1646 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001647 int i, j, conn_len = 0;
1648 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
1649 unsigned int wcaps, wtype;
1650
Mattc7d4b2f2005-06-27 14:59:41 +02001651 for (i = 0; i < cfg->line_outs; i++) {
1652 nid = cfg->line_out_pins[i];
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001653 conn_len = snd_hda_get_connections(codec, nid, conn,
1654 HDA_MAX_CONNECTIONS);
1655 for (j = 0; j < conn_len; j++) {
1656 wcaps = snd_hda_param_read(codec, conn[j],
1657 AC_PAR_AUDIO_WIDGET_CAP);
1658 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
1659
1660 if (wtype != AC_WID_AUD_OUT ||
1661 (wcaps & AC_WCAP_DIGITAL))
1662 continue;
1663 /* conn[j] is a DAC routed to this line-out */
1664 if (!is_in_dac_nids(spec, conn[j]))
1665 break;
1666 }
1667
1668 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02001669 if (spec->multiout.num_dacs > 0) {
1670 /* we have already working output pins,
1671 * so let's drop the broken ones again
1672 */
1673 cfg->line_outs = spec->multiout.num_dacs;
1674 break;
1675 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001676 /* error out, no available DAC found */
1677 snd_printk(KERN_ERR
1678 "%s: No available DAC for pin 0x%x\n",
1679 __func__, nid);
1680 return -ENODEV;
1681 }
1682
1683 spec->multiout.dac_nids[i] = conn[j];
1684 spec->multiout.num_dacs++;
1685 if (conn_len > 1) {
1686 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001687 snd_hda_codec_write_cache(codec, nid, 0,
1688 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001689
1690 }
Mattc7d4b2f2005-06-27 14:59:41 +02001691 }
1692
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001693 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
1694 spec->multiout.num_dacs,
1695 spec->multiout.dac_nids[0],
1696 spec->multiout.dac_nids[1],
1697 spec->multiout.dac_nids[2],
1698 spec->multiout.dac_nids[3],
1699 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02001700 return 0;
1701}
1702
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001703/* create volume control/switch for the given prefx type */
1704static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
1705{
1706 char name[32];
1707 int err;
1708
1709 sprintf(name, "%s Playback Volume", pfx);
1710 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
1711 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
1712 if (err < 0)
1713 return err;
1714 sprintf(name, "%s Playback Switch", pfx);
1715 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
1716 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
1717 if (err < 0)
1718 return err;
1719 return 0;
1720}
1721
Mattc7d4b2f2005-06-27 14:59:41 +02001722/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001723static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001724 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02001725{
Takashi Iwai19039bd2006-06-28 15:52:16 +02001726 static const char *chname[4] = {
1727 "Front", "Surround", NULL /*CLFE*/, "Side"
1728 };
Mattc7d4b2f2005-06-27 14:59:41 +02001729 hda_nid_t nid;
1730 int i, err;
1731
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001732 struct sigmatel_spec *spec = codec->spec;
1733 unsigned int wid_caps;
1734
1735
Mattc7d4b2f2005-06-27 14:59:41 +02001736 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01001737 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02001738 continue;
1739
1740 nid = spec->multiout.dac_nids[i];
1741
1742 if (i == 2) {
1743 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001744 err = create_controls(spec, "Center", nid, 1);
1745 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02001746 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001747 err = create_controls(spec, "LFE", nid, 2);
1748 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02001749 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001750
1751 wid_caps = get_wcaps(codec, nid);
1752
1753 if (wid_caps & AC_WCAP_LR_SWAP) {
1754 err = stac92xx_add_control(spec,
1755 STAC_CTL_WIDGET_CLFE_SWITCH,
1756 "Swap Center/LFE Playback Switch", nid);
1757
1758 if (err < 0)
1759 return err;
1760 }
1761
Mattc7d4b2f2005-06-27 14:59:41 +02001762 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001763 err = create_controls(spec, chname[i], nid, 3);
1764 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02001765 return err;
1766 }
1767 }
1768
Matt Porter403d1942005-11-29 15:00:51 +01001769 if (spec->line_switch)
1770 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
1771 return err;
1772
1773 if (spec->mic_switch)
1774 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
1775 return err;
1776
Mattc7d4b2f2005-06-27 14:59:41 +02001777 return 0;
1778}
1779
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001780static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
1781{
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001782 if (is_in_dac_nids(spec, nid))
1783 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001784 if (spec->multiout.hp_nid == nid)
1785 return 1;
1786 return 0;
1787}
1788
1789static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
1790{
1791 if (!spec->multiout.hp_nid)
1792 spec->multiout.hp_nid = nid;
1793 else if (spec->multiout.num_dacs > 4) {
1794 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
1795 return 1;
1796 } else {
1797 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
1798 spec->multiout.num_dacs++;
1799 }
1800 return 0;
1801}
1802
1803/* add playback controls for Speaker and HP outputs */
1804static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
1805 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02001806{
1807 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02001808 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001809 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02001810
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001811 old_num_dacs = spec->multiout.num_dacs;
1812 for (i = 0; i < cfg->hp_outs; i++) {
1813 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
1814 if (wid_caps & AC_WCAP_UNSOL_CAP)
1815 spec->hp_detect = 1;
1816 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
1817 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
1818 if (check_in_dac_nids(spec, nid))
1819 nid = 0;
1820 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02001821 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001822 add_spec_dacs(spec, nid);
1823 }
1824 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001825 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001826 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
1827 if (check_in_dac_nids(spec, nid))
1828 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001829 if (! nid)
1830 continue;
1831 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02001832 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02001833 for (i = 0; i < cfg->line_outs; i++) {
1834 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
1835 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
1836 if (check_in_dac_nids(spec, nid))
1837 nid = 0;
1838 if (! nid)
1839 continue;
1840 add_spec_dacs(spec, nid);
1841 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001842 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
1843 static const char *pfxs[] = {
1844 "Speaker", "External Speaker", "Speaker2",
1845 };
1846 err = create_controls(spec, pfxs[i - old_num_dacs],
1847 spec->multiout.dac_nids[i], 3);
1848 if (err < 0)
1849 return err;
1850 }
1851 if (spec->multiout.hp_nid) {
1852 const char *pfx;
1853 if (old_num_dacs == spec->multiout.num_dacs)
1854 pfx = "Master";
1855 else
1856 pfx = "Headphone";
1857 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
1858 if (err < 0)
1859 return err;
1860 }
Mattc7d4b2f2005-06-27 14:59:41 +02001861
1862 return 0;
1863}
1864
Matt Porter8b657272006-10-26 17:12:59 +02001865/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01001866static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02001867 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
1868 "Digital Mic 3", "Digital Mic 4"
1869};
1870
1871/* create playback/capture controls for input pins on dmic capable codecs */
1872static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
1873 const struct auto_pin_cfg *cfg)
1874{
1875 struct sigmatel_spec *spec = codec->spec;
1876 struct hda_input_mux *dimux = &spec->private_dimux;
1877 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
1878 int i, j;
1879
1880 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
1881 dimux->items[dimux->num_items].index = 0;
1882 dimux->num_items++;
1883
1884 for (i = 0; i < spec->num_dmics; i++) {
1885 int index;
1886 int num_cons;
1887 unsigned int def_conf;
1888
1889 def_conf = snd_hda_codec_read(codec,
1890 spec->dmic_nids[i],
1891 0,
1892 AC_VERB_GET_CONFIG_DEFAULT,
1893 0);
1894 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
1895 continue;
1896
1897 num_cons = snd_hda_get_connections(codec,
1898 spec->dmux_nid,
1899 con_lst,
1900 HDA_MAX_NUM_INPUTS);
1901 for (j = 0; j < num_cons; j++)
1902 if (con_lst[j] == spec->dmic_nids[i]) {
1903 index = j;
1904 goto found;
1905 }
1906 continue;
1907found:
1908 dimux->items[dimux->num_items].label =
1909 stac92xx_dmic_labels[dimux->num_items];
1910 dimux->items[dimux->num_items].index = index;
1911 dimux->num_items++;
1912 }
1913
1914 return 0;
1915}
1916
Mattc7d4b2f2005-06-27 14:59:41 +02001917/* create playback/capture controls for input pins */
1918static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
1919{
1920 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02001921 struct hda_input_mux *imux = &spec->private_imux;
1922 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
1923 int i, j, k;
1924
1925 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02001926 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02001927
Takashi Iwai314634b2006-09-21 11:56:18 +02001928 if (!cfg->input_pins[i])
1929 continue;
1930 index = -1;
1931 for (j = 0; j < spec->num_muxes; j++) {
1932 int num_cons;
1933 num_cons = snd_hda_get_connections(codec,
1934 spec->mux_nids[j],
1935 con_lst,
1936 HDA_MAX_NUM_INPUTS);
1937 for (k = 0; k < num_cons; k++)
1938 if (con_lst[k] == cfg->input_pins[i]) {
1939 index = k;
1940 goto found;
1941 }
Mattc7d4b2f2005-06-27 14:59:41 +02001942 }
Takashi Iwai314634b2006-09-21 11:56:18 +02001943 continue;
1944 found:
1945 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
1946 imux->items[imux->num_items].index = index;
1947 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02001948 }
1949
Steve Longerbeam7b0438992007-05-03 20:50:03 +02001950 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02001951 /*
1952 * Set the current input for the muxes.
1953 * The STAC9221 has two input muxes with identical source
1954 * NID lists. Hopefully this won't get confused.
1955 */
1956 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001957 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
1958 AC_VERB_SET_CONNECT_SEL,
1959 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02001960 }
1961 }
1962
Mattc7d4b2f2005-06-27 14:59:41 +02001963 return 0;
1964}
1965
Mattc7d4b2f2005-06-27 14:59:41 +02001966static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
1967{
1968 struct sigmatel_spec *spec = codec->spec;
1969 int i;
1970
1971 for (i = 0; i < spec->autocfg.line_outs; i++) {
1972 hda_nid_t nid = spec->autocfg.line_out_pins[i];
1973 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
1974 }
1975}
1976
1977static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
1978{
1979 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001980 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02001981
Takashi Iwaieb06ed82006-09-20 17:10:27 +02001982 for (i = 0; i < spec->autocfg.hp_outs; i++) {
1983 hda_nid_t pin;
1984 pin = spec->autocfg.hp_pins[i];
1985 if (pin) /* connect to front */
1986 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
1987 }
1988 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
1989 hda_nid_t pin;
1990 pin = spec->autocfg.speaker_pins[i];
1991 if (pin) /* connect to front */
1992 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
1993 }
Mattc7d4b2f2005-06-27 14:59:41 +02001994}
1995
Matt Porter3cc08dc2006-01-23 15:27:49 +01001996static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
Mattc7d4b2f2005-06-27 14:59:41 +02001997{
1998 struct sigmatel_spec *spec = codec->spec;
1999 int err;
2000
Matt Porter8b657272006-10-26 17:12:59 +02002001 if ((err = snd_hda_parse_pin_def_config(codec,
2002 &spec->autocfg,
2003 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002004 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002005 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002006 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002007
Matt Porter403d1942005-11-29 15:00:51 +01002008 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2009 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002010 if (spec->multiout.num_dacs == 0)
2011 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2012 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002013
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002014 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2015
2016 if (err < 0)
2017 return err;
2018
2019 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2020
2021 if (err < 0)
2022 return err;
2023
2024 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2025
2026 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002027 return err;
2028
Matt Porter8b657272006-10-26 17:12:59 +02002029 if (spec->num_dmics > 0)
2030 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2031 &spec->autocfg)) < 0)
2032 return err;
2033
Mattc7d4b2f2005-06-27 14:59:41 +02002034 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002035 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002036 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002037
Takashi Iwai82bc9552006-03-21 11:24:42 +01002038 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002039 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002040 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002041 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002042
2043 if (spec->kctl_alloc)
2044 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2045
2046 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002047 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002048
2049 return 1;
2050}
2051
Takashi Iwai82bc9552006-03-21 11:24:42 +01002052/* add playback controls for HP output */
2053static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2054 struct auto_pin_cfg *cfg)
2055{
2056 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002057 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002058 unsigned int wid_caps;
2059
2060 if (! pin)
2061 return 0;
2062
2063 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002064 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002065 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002066
2067 return 0;
2068}
2069
Richard Fish160ea0d2006-09-06 13:58:25 +02002070/* add playback controls for LFE output */
2071static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2072 struct auto_pin_cfg *cfg)
2073{
2074 struct sigmatel_spec *spec = codec->spec;
2075 int err;
2076 hda_nid_t lfe_pin = 0x0;
2077 int i;
2078
2079 /*
2080 * search speaker outs and line outs for a mono speaker pin
2081 * with an amp. If one is found, add LFE controls
2082 * for it.
2083 */
2084 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2085 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2086 unsigned long wcaps = get_wcaps(codec, pin);
2087 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2088 if (wcaps == AC_WCAP_OUT_AMP)
2089 /* found a mono speaker with an amp, must be lfe */
2090 lfe_pin = pin;
2091 }
2092
2093 /* if speaker_outs is 0, then speakers may be in line_outs */
2094 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2095 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2096 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2097 unsigned long cfg;
2098 cfg = snd_hda_codec_read(codec, pin, 0,
2099 AC_VERB_GET_CONFIG_DEFAULT,
2100 0x00);
2101 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2102 unsigned long wcaps = get_wcaps(codec, pin);
2103 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2104 if (wcaps == AC_WCAP_OUT_AMP)
2105 /* found a mono speaker with an amp,
2106 must be lfe */
2107 lfe_pin = pin;
2108 }
2109 }
2110 }
2111
2112 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002113 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002114 if (err < 0)
2115 return err;
2116 }
2117
2118 return 0;
2119}
2120
Mattc7d4b2f2005-06-27 14:59:41 +02002121static int stac9200_parse_auto_config(struct hda_codec *codec)
2122{
2123 struct sigmatel_spec *spec = codec->spec;
2124 int err;
2125
Kailang Yangdf694da2005-12-05 19:42:22 +01002126 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002127 return err;
2128
2129 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2130 return err;
2131
Takashi Iwai82bc9552006-03-21 11:24:42 +01002132 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2133 return err;
2134
Richard Fish160ea0d2006-09-06 13:58:25 +02002135 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2136 return err;
2137
Takashi Iwai82bc9552006-03-21 11:24:42 +01002138 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002139 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002140 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002141 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002142
2143 if (spec->kctl_alloc)
2144 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2145
2146 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002147 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002148
2149 return 1;
2150}
2151
Sam Revitch62fe78e2006-05-10 15:09:17 +02002152/*
2153 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2154 * funky external mute control using GPIO pins.
2155 */
2156
2157static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
2158{
2159 unsigned int gpiostate, gpiomask, gpiodir;
2160
2161 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2162 AC_VERB_GET_GPIO_DATA, 0);
2163
2164 if (!muted)
2165 gpiostate |= (1 << pin);
2166 else
2167 gpiostate &= ~(1 << pin);
2168
2169 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2170 AC_VERB_GET_GPIO_MASK, 0);
2171 gpiomask |= (1 << pin);
2172
2173 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2174 AC_VERB_GET_GPIO_DIRECTION, 0);
2175 gpiodir |= (1 << pin);
2176
2177 /* AppleHDA seems to do this -- WTF is this verb?? */
2178 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2179
2180 snd_hda_codec_write(codec, codec->afg, 0,
2181 AC_VERB_SET_GPIO_MASK, gpiomask);
2182 snd_hda_codec_write(codec, codec->afg, 0,
2183 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
2184
2185 msleep(1);
2186
2187 snd_hda_codec_write(codec, codec->afg, 0,
2188 AC_VERB_SET_GPIO_DATA, gpiostate);
2189}
2190
Takashi Iwai314634b2006-09-21 11:56:18 +02002191static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2192 unsigned int event)
2193{
2194 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002195 snd_hda_codec_write_cache(codec, nid, 0,
2196 AC_VERB_SET_UNSOLICITED_ENABLE,
2197 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002198}
2199
Mattc7d4b2f2005-06-27 14:59:41 +02002200static int stac92xx_init(struct hda_codec *codec)
2201{
2202 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002203 struct auto_pin_cfg *cfg = &spec->autocfg;
2204 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002205
Mattc7d4b2f2005-06-27 14:59:41 +02002206 snd_hda_sequence_write(codec, spec->init);
2207
Takashi Iwai82bc9552006-03-21 11:24:42 +01002208 /* set up pins */
2209 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002210 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002211 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002212 enable_pin_detect(codec, cfg->hp_pins[i],
2213 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002214 /* force to enable the first line-out; the others are set up
2215 * in unsol_event
2216 */
2217 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2218 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002219 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002220 /* fake event to set up pins */
2221 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2222 } else {
2223 stac92xx_auto_init_multi_out(codec);
2224 stac92xx_auto_init_hp_out(codec);
2225 }
2226 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002227 hda_nid_t nid = cfg->input_pins[i];
2228 if (nid) {
2229 unsigned int pinctl = AC_PINCTL_IN_EN;
2230 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2231 pinctl |= stac92xx_get_vref(codec, nid);
2232 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2233 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002234 }
Matt Porter8b657272006-10-26 17:12:59 +02002235 if (spec->num_dmics > 0)
2236 for (i = 0; i < spec->num_dmics; i++)
2237 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2238 AC_PINCTL_IN_EN);
2239
Takashi Iwai82bc9552006-03-21 11:24:42 +01002240 if (cfg->dig_out_pin)
2241 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2242 AC_PINCTL_OUT_EN);
2243 if (cfg->dig_in_pin)
2244 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2245 AC_PINCTL_IN_EN);
2246
Sam Revitch62fe78e2006-05-10 15:09:17 +02002247 if (spec->gpio_mute) {
2248 stac922x_gpio_mute(codec, 0, 0);
2249 stac922x_gpio_mute(codec, 1, 0);
2250 }
2251
Mattc7d4b2f2005-06-27 14:59:41 +02002252 return 0;
2253}
2254
Matt2f2f4252005-04-13 14:45:30 +02002255static void stac92xx_free(struct hda_codec *codec)
2256{
Mattc7d4b2f2005-06-27 14:59:41 +02002257 struct sigmatel_spec *spec = codec->spec;
2258 int i;
2259
2260 if (! spec)
2261 return;
2262
2263 if (spec->kctl_alloc) {
2264 for (i = 0; i < spec->num_kctl_used; i++)
2265 kfree(spec->kctl_alloc[i].name);
2266 kfree(spec->kctl_alloc);
2267 }
2268
Richard Fish11b44bb2006-08-23 18:31:34 +02002269 if (spec->bios_pin_configs)
2270 kfree(spec->bios_pin_configs);
2271
Mattc7d4b2f2005-06-27 14:59:41 +02002272 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002273}
2274
Matt4e550962005-07-04 17:51:39 +02002275static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2276 unsigned int flag)
2277{
2278 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2279 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002280
Takashi Iwaif9acba42007-05-29 18:01:06 +02002281 if (pin_ctl & AC_PINCTL_IN_EN) {
2282 /*
2283 * we need to check the current set-up direction of
2284 * shared input pins since they can be switched via
2285 * "xxx as Output" mixer switch
2286 */
2287 struct sigmatel_spec *spec = codec->spec;
2288 struct auto_pin_cfg *cfg = &spec->autocfg;
2289 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2290 spec->line_switch) ||
2291 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2292 spec->mic_switch))
2293 return;
2294 }
2295
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002296 /* if setting pin direction bits, clear the current
2297 direction bits first */
2298 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2299 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2300
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002301 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002302 AC_VERB_SET_PIN_WIDGET_CONTROL,
2303 pin_ctl | flag);
2304}
2305
2306static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2307 unsigned int flag)
2308{
2309 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2310 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002311 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002312 AC_VERB_SET_PIN_WIDGET_CONTROL,
2313 pin_ctl & ~flag);
2314}
2315
Takashi Iwai314634b2006-09-21 11:56:18 +02002316static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
2317{
2318 if (!nid)
2319 return 0;
2320 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
2321 & (1 << 31))
2322 return 1;
2323 return 0;
2324}
2325
2326static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02002327{
2328 struct sigmatel_spec *spec = codec->spec;
2329 struct auto_pin_cfg *cfg = &spec->autocfg;
2330 int i, presence;
2331
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002332 presence = 0;
2333 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002334 presence = get_pin_presence(codec, cfg->hp_pins[i]);
2335 if (presence)
2336 break;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002337 }
Matt4e550962005-07-04 17:51:39 +02002338
2339 if (presence) {
2340 /* disable lineouts, enable hp */
2341 for (i = 0; i < cfg->line_outs; i++)
2342 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
2343 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002344 for (i = 0; i < cfg->speaker_outs; i++)
2345 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
2346 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002347 } else {
2348 /* enable lineouts, disable hp */
2349 for (i = 0; i < cfg->line_outs; i++)
2350 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
2351 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002352 for (i = 0; i < cfg->speaker_outs; i++)
2353 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
2354 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002355 }
2356}
2357
Takashi Iwai314634b2006-09-21 11:56:18 +02002358static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
2359{
2360 switch (res >> 26) {
2361 case STAC_HP_EVENT:
2362 stac92xx_hp_detect(codec, res);
2363 break;
2364 }
2365}
2366
Takashi Iwaicb53c622007-08-10 17:21:45 +02002367#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002368static int stac92xx_resume(struct hda_codec *codec)
2369{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002370 struct sigmatel_spec *spec = codec->spec;
2371
Richard Fish11b44bb2006-08-23 18:31:34 +02002372 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002373 snd_hda_sequence_write(codec, spec->init);
2374 if (spec->gpio_mute) {
2375 stac922x_gpio_mute(codec, 0, 0);
2376 stac922x_gpio_mute(codec, 1, 0);
2377 }
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002378 snd_hda_codec_resume_amp(codec);
2379 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002380 /* invoke unsolicited event to reset the HP state */
2381 if (spec->hp_detect)
2382 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02002383 return 0;
2384}
2385#endif
2386
Matt2f2f4252005-04-13 14:45:30 +02002387static struct hda_codec_ops stac92xx_patch_ops = {
2388 .build_controls = stac92xx_build_controls,
2389 .build_pcms = stac92xx_build_pcms,
2390 .init = stac92xx_init,
2391 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02002392 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002393#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002394 .resume = stac92xx_resume,
2395#endif
Matt2f2f4252005-04-13 14:45:30 +02002396};
2397
2398static int patch_stac9200(struct hda_codec *codec)
2399{
2400 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002401 int err;
Matt2f2f4252005-04-13 14:45:30 +02002402
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002403 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02002404 if (spec == NULL)
2405 return -ENOMEM;
2406
2407 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002408 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002409 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002410 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
2411 stac9200_models,
2412 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02002413 if (spec->board_config < 0) {
2414 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
2415 err = stac92xx_save_bios_config_regs(codec);
2416 if (err < 0) {
2417 stac92xx_free(codec);
2418 return err;
2419 }
2420 spec->pin_configs = spec->bios_pin_configs;
2421 } else {
Matt Porter403d1942005-11-29 15:00:51 +01002422 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
2423 stac92xx_set_config_regs(codec);
2424 }
Matt2f2f4252005-04-13 14:45:30 +02002425
2426 spec->multiout.max_channels = 2;
2427 spec->multiout.num_dacs = 1;
2428 spec->multiout.dac_nids = stac9200_dac_nids;
2429 spec->adc_nids = stac9200_adc_nids;
2430 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02002431 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02002432 spec->num_dmics = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002433
2434 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02002435 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02002436
2437 err = stac9200_parse_auto_config(codec);
2438 if (err < 0) {
2439 stac92xx_free(codec);
2440 return err;
2441 }
Matt2f2f4252005-04-13 14:45:30 +02002442
2443 codec->patch_ops = stac92xx_patch_ops;
2444
2445 return 0;
2446}
2447
Tobin Davis8e21c342007-01-08 11:04:17 +01002448static int patch_stac925x(struct hda_codec *codec)
2449{
2450 struct sigmatel_spec *spec;
2451 int err;
2452
2453 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2454 if (spec == NULL)
2455 return -ENOMEM;
2456
2457 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002458 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01002459 spec->pin_nids = stac925x_pin_nids;
2460 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
2461 stac925x_models,
2462 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002463 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01002464 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02002465 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
2466 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01002467 err = stac92xx_save_bios_config_regs(codec);
2468 if (err < 0) {
2469 stac92xx_free(codec);
2470 return err;
2471 }
2472 spec->pin_configs = spec->bios_pin_configs;
2473 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
2474 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
2475 stac92xx_set_config_regs(codec);
2476 }
2477
2478 spec->multiout.max_channels = 2;
2479 spec->multiout.num_dacs = 1;
2480 spec->multiout.dac_nids = stac925x_dac_nids;
2481 spec->adc_nids = stac925x_adc_nids;
2482 spec->mux_nids = stac925x_mux_nids;
2483 spec->num_muxes = 1;
Tobin Davis2c11f952007-05-17 09:36:34 +02002484 switch (codec->vendor_id) {
2485 case 0x83847632: /* STAC9202 */
2486 case 0x83847633: /* STAC9202D */
2487 case 0x83847636: /* STAC9251 */
2488 case 0x83847637: /* STAC9251D */
2489 spec->num_dmics = 1;
2490 spec->dmic_nids = stac925x_dmic_nids;
2491 break;
2492 default:
2493 spec->num_dmics = 0;
2494 break;
2495 }
Tobin Davis8e21c342007-01-08 11:04:17 +01002496
2497 spec->init = stac925x_core_init;
2498 spec->mixer = stac925x_mixer;
2499
2500 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002501 if (!err) {
2502 if (spec->board_config < 0) {
2503 printk(KERN_WARNING "hda_codec: No auto-config is "
2504 "available, default to model=ref\n");
2505 spec->board_config = STAC_925x_REF;
2506 goto again;
2507 }
2508 err = -EINVAL;
2509 }
Tobin Davis8e21c342007-01-08 11:04:17 +01002510 if (err < 0) {
2511 stac92xx_free(codec);
2512 return err;
2513 }
2514
2515 codec->patch_ops = stac92xx_patch_ops;
2516
2517 return 0;
2518}
2519
Matt2f2f4252005-04-13 14:45:30 +02002520static int patch_stac922x(struct hda_codec *codec)
2521{
2522 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002523 int err;
Matt2f2f4252005-04-13 14:45:30 +02002524
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002525 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02002526 if (spec == NULL)
2527 return -ENOMEM;
2528
2529 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002530 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002531 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002532 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
2533 stac922x_models,
2534 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002535 if (spec->board_config == STAC_INTEL_MAC_V3) {
Takashi Iwai3fc24d82007-02-16 13:27:18 +01002536 spec->gpio_mute = 1;
2537 /* Intel Macs have all same PCI SSID, so we need to check
2538 * codec SSID to distinguish the exact models
2539 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01002540 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01002541 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002542
2543 case 0x106b0800:
2544 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02002545 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002546 case 0x106b0600:
2547 case 0x106b0700:
2548 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01002549 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002550 case 0x106b0e00:
2551 case 0x106b0f00:
2552 case 0x106b1600:
2553 case 0x106b1700:
2554 case 0x106b0200:
2555 case 0x106b1e00:
2556 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01002557 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002558 case 0x106b1a00:
2559 case 0x00000100:
2560 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02002561 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002562 case 0x106b0a00:
2563 case 0x106b2200:
2564 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02002565 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01002566 }
2567 }
2568
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002569 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02002570 if (spec->board_config < 0) {
2571 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
2572 "using BIOS defaults\n");
2573 err = stac92xx_save_bios_config_regs(codec);
2574 if (err < 0) {
2575 stac92xx_free(codec);
2576 return err;
2577 }
2578 spec->pin_configs = spec->bios_pin_configs;
2579 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01002580 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
2581 stac92xx_set_config_regs(codec);
2582 }
Matt2f2f4252005-04-13 14:45:30 +02002583
Matt2f2f4252005-04-13 14:45:30 +02002584 spec->adc_nids = stac922x_adc_nids;
2585 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01002586 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02002587 spec->num_dmics = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002588
2589 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02002590 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02002591
2592 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002593
Matt Porter3cc08dc2006-01-23 15:27:49 +01002594 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002595 if (!err) {
2596 if (spec->board_config < 0) {
2597 printk(KERN_WARNING "hda_codec: No auto-config is "
2598 "available, default to model=ref\n");
2599 spec->board_config = STAC_D945_REF;
2600 goto again;
2601 }
2602 err = -EINVAL;
2603 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01002604 if (err < 0) {
2605 stac92xx_free(codec);
2606 return err;
2607 }
2608
2609 codec->patch_ops = stac92xx_patch_ops;
2610
Takashi Iwai807a46362007-05-29 19:01:37 +02002611 /* Fix Mux capture level; max to 2 */
2612 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
2613 (0 << AC_AMPCAP_OFFSET_SHIFT) |
2614 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2615 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2616 (0 << AC_AMPCAP_MUTE_SHIFT));
2617
Matt Porter3cc08dc2006-01-23 15:27:49 +01002618 return 0;
2619}
2620
2621static int patch_stac927x(struct hda_codec *codec)
2622{
2623 struct sigmatel_spec *spec;
2624 int err;
2625
2626 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2627 if (spec == NULL)
2628 return -ENOMEM;
2629
2630 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002631 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002632 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002633 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
2634 stac927x_models,
2635 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002636 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02002637 if (spec->board_config < 0) {
Matt Porter3cc08dc2006-01-23 15:27:49 +01002638 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02002639 err = stac92xx_save_bios_config_regs(codec);
2640 if (err < 0) {
2641 stac92xx_free(codec);
2642 return err;
2643 }
2644 spec->pin_configs = spec->bios_pin_configs;
2645 } else if (stac927x_brd_tbl[spec->board_config] != NULL) {
Matt Porter3cc08dc2006-01-23 15:27:49 +01002646 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
2647 stac92xx_set_config_regs(codec);
2648 }
2649
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002650 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02002651 case STAC_D965_3ST:
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002652 spec->adc_nids = stac927x_adc_nids;
2653 spec->mux_nids = stac927x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01002654 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02002655 spec->num_dmics = 0;
Tobin Davis93ed1502006-09-01 21:03:12 +02002656 spec->init = d965_core_init;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002657 spec->mixer = stac9227_mixer;
2658 break;
Tobin Davis93ed1502006-09-01 21:03:12 +02002659 case STAC_D965_5ST:
2660 spec->adc_nids = stac927x_adc_nids;
2661 spec->mux_nids = stac927x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01002662 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02002663 spec->num_dmics = 0;
Tobin Davis93ed1502006-09-01 21:03:12 +02002664 spec->init = d965_core_init;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002665 spec->mixer = stac9227_mixer;
2666 break;
2667 default:
2668 spec->adc_nids = stac927x_adc_nids;
2669 spec->mux_nids = stac927x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01002670 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02002671 spec->num_dmics = 0;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002672 spec->init = stac927x_core_init;
2673 spec->mixer = stac927x_mixer;
2674 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01002675
2676 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02002677 /* GPIO0 High = Enable EAPD */
Takashi Iwai82599802007-07-31 15:56:24 +02002678 spec->gpio_mask = spec->gpio_data = 0x00000001;
2679 stac92xx_enable_gpio_mask(codec);
Matthew Ranostay92a22be2007-06-19 16:48:28 +02002680
Matt Porter3cc08dc2006-01-23 15:27:49 +01002681 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002682 if (!err) {
2683 if (spec->board_config < 0) {
2684 printk(KERN_WARNING "hda_codec: No auto-config is "
2685 "available, default to model=ref\n");
2686 spec->board_config = STAC_D965_REF;
2687 goto again;
2688 }
2689 err = -EINVAL;
2690 }
Mattc7d4b2f2005-06-27 14:59:41 +02002691 if (err < 0) {
2692 stac92xx_free(codec);
2693 return err;
2694 }
Matt2f2f4252005-04-13 14:45:30 +02002695
2696 codec->patch_ops = stac92xx_patch_ops;
2697
2698 return 0;
2699}
2700
Matt Porterf3302a52006-07-31 12:49:34 +02002701static int patch_stac9205(struct hda_codec *codec)
2702{
2703 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02002704 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02002705
2706 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2707 if (spec == NULL)
2708 return -ENOMEM;
2709
2710 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002711 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002712 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002713 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
2714 stac9205_models,
2715 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002716 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02002717 if (spec->board_config < 0) {
2718 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
2719 err = stac92xx_save_bios_config_regs(codec);
2720 if (err < 0) {
2721 stac92xx_free(codec);
2722 return err;
2723 }
2724 spec->pin_configs = spec->bios_pin_configs;
2725 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02002726 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
2727 stac92xx_set_config_regs(codec);
2728 }
2729
2730 spec->adc_nids = stac9205_adc_nids;
2731 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01002732 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02002733 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01002734 spec->num_dmics = ARRAY_SIZE(stac9205_dmic_nids);
Matt Porter8b657272006-10-26 17:12:59 +02002735 spec->dmux_nid = 0x1d;
Matt Porterf3302a52006-07-31 12:49:34 +02002736
2737 spec->init = stac9205_core_init;
2738 spec->mixer = stac9205_mixer;
2739
2740 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02002741
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002742 switch (spec->board_config){
2743 case STAC_9205_M43xx:
2744 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02002745 /* Enable SPDIF in/out */
2746 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
2747 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01002748
Takashi Iwai82599802007-07-31 15:56:24 +02002749 spec->gpio_mask = 0x00000007; /* GPIO0-2 */
Matthew Ranostay87d48362007-07-17 11:52:24 +02002750 /* GPIO0 High = EAPD, GPIO1 Low = DRM,
2751 * GPIO2 High = Headphone Mute
2752 */
Takashi Iwai82599802007-07-31 15:56:24 +02002753 spec->gpio_data = 0x00000005;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002754 break;
2755 default:
2756 /* GPIO0 High = EAPD */
2757 spec->gpio_mask = spec->gpio_data = 0x00000001;
2758 break;
2759 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02002760
Takashi Iwai82599802007-07-31 15:56:24 +02002761 stac92xx_enable_gpio_mask(codec);
Matt Porterf3302a52006-07-31 12:49:34 +02002762 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002763 if (!err) {
2764 if (spec->board_config < 0) {
2765 printk(KERN_WARNING "hda_codec: No auto-config is "
2766 "available, default to model=ref\n");
2767 spec->board_config = STAC_9205_REF;
2768 goto again;
2769 }
2770 err = -EINVAL;
2771 }
Matt Porterf3302a52006-07-31 12:49:34 +02002772 if (err < 0) {
2773 stac92xx_free(codec);
2774 return err;
2775 }
2776
2777 codec->patch_ops = stac92xx_patch_ops;
2778
2779 return 0;
2780}
2781
Matt2f2f4252005-04-13 14:45:30 +02002782/*
Guillaume Munch6d859062006-08-22 17:15:47 +02002783 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01002784 */
2785
Guillaume Munch99ccc562006-08-16 19:35:12 +02002786/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01002787static hda_nid_t vaio_dacs[] = { 0x2 };
2788#define VAIO_HP_DAC 0x5
2789static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
2790static hda_nid_t vaio_mux_nids[] = { 0x15 };
2791
2792static struct hda_input_mux vaio_mux = {
2793 .num_items = 2,
2794 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02002795 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02002796 { "Mic Jack", 0x1 },
2797 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01002798 { "PCM", 0x3 },
2799 }
2800};
2801
2802static struct hda_verb vaio_init[] = {
2803 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02002804 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01002805 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
2806 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
2807 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
2808 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02002809 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01002810 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
2811 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
2812 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
2813 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
2814 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
2815 {}
2816};
2817
Guillaume Munch6d859062006-08-22 17:15:47 +02002818static struct hda_verb vaio_ar_init[] = {
2819 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
2820 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
2821 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
2822 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
2823/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
2824 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02002825 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02002826 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
2827 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
2828/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
2829 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
2830 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
2831 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
2832 {}
2833};
2834
Takashi Iwaidb064e52006-03-16 16:04:58 +01002835/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02002836static struct hda_bind_ctls vaio_bind_master_vol = {
2837 .ops = &snd_hda_bind_vol,
2838 .values = {
2839 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
2840 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
2841 0
2842 },
2843};
Takashi Iwaidb064e52006-03-16 16:04:58 +01002844
2845/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02002846static struct hda_bind_ctls vaio_bind_master_sw = {
2847 .ops = &snd_hda_bind_sw,
2848 .values = {
2849 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
2850 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
2851 0,
2852 },
2853};
Takashi Iwaidb064e52006-03-16 16:04:58 +01002854
2855static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02002856 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
2857 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01002858 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
2859 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
2860 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
2861 {
2862 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2863 .name = "Capture Source",
2864 .count = 1,
2865 .info = stac92xx_mux_enum_info,
2866 .get = stac92xx_mux_enum_get,
2867 .put = stac92xx_mux_enum_put,
2868 },
2869 {}
2870};
2871
Guillaume Munch6d859062006-08-22 17:15:47 +02002872static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02002873 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
2874 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02002875 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
2876 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
2877 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
2878 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
2879 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
2880 {
2881 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2882 .name = "Capture Source",
2883 .count = 1,
2884 .info = stac92xx_mux_enum_info,
2885 .get = stac92xx_mux_enum_get,
2886 .put = stac92xx_mux_enum_put,
2887 },
2888 {}
2889};
2890
2891static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01002892 .build_controls = stac92xx_build_controls,
2893 .build_pcms = stac92xx_build_pcms,
2894 .init = stac92xx_init,
2895 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002896#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01002897 .resume = stac92xx_resume,
2898#endif
2899};
2900
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02002901static int stac9872_vaio_init(struct hda_codec *codec)
2902{
2903 int err;
2904
2905 err = stac92xx_init(codec);
2906 if (err < 0)
2907 return err;
2908 if (codec->patch_ops.unsol_event)
2909 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2910 return 0;
2911}
2912
2913static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
2914{
2915 if (get_pin_presence(codec, 0x0a)) {
2916 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
2917 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
2918 } else {
2919 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
2920 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
2921 }
2922}
2923
2924static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
2925{
2926 switch (res >> 26) {
2927 case STAC_HP_EVENT:
2928 stac9872_vaio_hp_detect(codec, res);
2929 break;
2930 }
2931}
2932
2933static struct hda_codec_ops stac9872_vaio_patch_ops = {
2934 .build_controls = stac92xx_build_controls,
2935 .build_pcms = stac92xx_build_pcms,
2936 .init = stac9872_vaio_init,
2937 .free = stac92xx_free,
2938 .unsol_event = stac9872_vaio_unsol_event,
2939#ifdef CONFIG_PM
2940 .resume = stac92xx_resume,
2941#endif
2942};
2943
Guillaume Munch6d859062006-08-22 17:15:47 +02002944enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
2945 CXD9872RD_VAIO,
2946 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
2947 STAC9872AK_VAIO,
2948 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
2949 STAC9872K_VAIO,
2950 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002951 CXD9872AKD_VAIO,
2952 STAC_9872_MODELS,
2953};
Takashi Iwaidb064e52006-03-16 16:04:58 +01002954
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002955static const char *stac9872_models[STAC_9872_MODELS] = {
2956 [CXD9872RD_VAIO] = "vaio",
2957 [CXD9872AKD_VAIO] = "vaio-ar",
2958};
2959
2960static struct snd_pci_quirk stac9872_cfg_tbl[] = {
2961 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
2962 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
2963 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01002964 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01002965 {}
2966};
2967
Guillaume Munch6d859062006-08-22 17:15:47 +02002968static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01002969{
2970 struct sigmatel_spec *spec;
2971 int board_config;
2972
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002973 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
2974 stac9872_models,
2975 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01002976 if (board_config < 0)
2977 /* unknown config, let generic-parser do its job... */
2978 return snd_hda_parse_generic_codec(codec);
2979
2980 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2981 if (spec == NULL)
2982 return -ENOMEM;
2983
2984 codec->spec = spec;
2985 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02002986 case CXD9872RD_VAIO:
2987 case STAC9872AK_VAIO:
2988 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01002989 spec->mixer = vaio_mixer;
2990 spec->init = vaio_init;
2991 spec->multiout.max_channels = 2;
2992 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
2993 spec->multiout.dac_nids = vaio_dacs;
2994 spec->multiout.hp_nid = VAIO_HP_DAC;
2995 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
2996 spec->adc_nids = vaio_adcs;
2997 spec->input_mux = &vaio_mux;
2998 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02002999 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003000 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003001
3002 case CXD9872AKD_VAIO:
3003 spec->mixer = vaio_ar_mixer;
3004 spec->init = vaio_ar_init;
3005 spec->multiout.max_channels = 2;
3006 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3007 spec->multiout.dac_nids = vaio_dacs;
3008 spec->multiout.hp_nid = VAIO_HP_DAC;
3009 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3010 spec->adc_nids = vaio_adcs;
3011 spec->input_mux = &vaio_mux;
3012 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003013 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003014 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003015 }
3016
Takashi Iwaidb064e52006-03-16 16:04:58 +01003017 return 0;
3018}
3019
3020
3021/*
Matt2f2f4252005-04-13 14:45:30 +02003022 * patch entries
3023 */
3024struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3025 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3026 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3027 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3028 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3029 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3030 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3031 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003032 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3033 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3034 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3035 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3036 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
3037 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01003038 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
3039 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
3040 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
3041 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
3042 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
3043 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
3044 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
3045 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
3046 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
3047 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01003048 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
3049 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
3050 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
3051 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
3052 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
3053 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02003054 /* The following does not take into account .id=0x83847661 when subsys =
3055 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
3056 * currently not fully supported.
3057 */
3058 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
3059 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
3060 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02003061 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
3062 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
3063 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
3064 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
3065 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
3066 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
3067 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
3068 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matt2f2f4252005-04-13 14:45:30 +02003069 {} /* terminator */
3070};