blob: 46c237b0e694d11633346d680d325fffe436e710 [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
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
35
Matt4e550962005-07-04 17:51:39 +020036#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010037#define STAC_PWR_EVENT 0x20
38#define STAC_HP_EVENT 0x30
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 Iwai1194b5b2007-10-10 10:04:26 +020052 STAC_9200_GATEWAY,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010053 STAC_9200_MODELS
54};
55
56enum {
57 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020058 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020059 STAC_9205_DELL_M43,
60 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010061 STAC_9205_MODELS
62};
63
64enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010065 STAC_92HD73XX_REF,
66 STAC_92HD73XX_MODELS
67};
68
69enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010070 STAC_92HD71BXX_REF,
71 STAC_92HD71BXX_MODELS
72};
73
74enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010075 STAC_925x_REF,
76 STAC_M2_2,
77 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020078 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010079 STAC_925x_MODELS
80};
81
82enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010083 STAC_D945_REF,
84 STAC_D945GTP3,
85 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020086 STAC_INTEL_MAC_V1,
87 STAC_INTEL_MAC_V2,
88 STAC_INTEL_MAC_V3,
89 STAC_INTEL_MAC_V4,
90 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020091 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010092 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010093 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010094 STAC_MACBOOK_PRO_V1,
95 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +020096 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +020097 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020098 STAC_922X_DELL_D81,
99 STAC_922X_DELL_D82,
100 STAC_922X_DELL_M81,
101 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100102 STAC_922X_MODELS
103};
104
105enum {
106 STAC_D965_REF,
107 STAC_D965_3ST,
108 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200109 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100110 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100111 STAC_927X_MODELS
112};
Matt Porter403d1942005-11-29 15:00:51 +0100113
Matt2f2f4252005-04-13 14:45:30 +0200114struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100115 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200116 unsigned int num_mixers;
117
Matt Porter403d1942005-11-29 15:00:51 +0100118 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200119 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100120 unsigned int line_switch: 1;
121 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100122 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100123 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200124
Takashi Iwai82599802007-07-31 15:56:24 +0200125 unsigned int gpio_mask, gpio_data;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100126 unsigned char aloopback_mask;
127 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200128
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100129 /* power management */
130 unsigned int num_pwrs;
131 hda_nid_t *pwr_nids;
132
Matt2f2f4252005-04-13 14:45:30 +0200133 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100134 struct hda_input_mux *mono_mux;
135 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200136 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100137 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200138
139 /* capture */
140 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200141 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200142 hda_nid_t *mux_nids;
143 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200144 hda_nid_t *dmic_nids;
145 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100146 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100147 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200148 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100149 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200150
Matt2f2f4252005-04-13 14:45:30 +0200151 /* pin widgets */
152 hda_nid_t *pin_nids;
153 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200154 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200155 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200156
157 /* codec specific stuff */
158 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100159 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200160
161 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200162 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100163 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200164 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100165 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200166
Matt Porter403d1942005-11-29 15:00:51 +0100167 /* i/o switches */
168 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200169 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200170 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200171
Mattc7d4b2f2005-06-27 14:59:41 +0200172 struct hda_pcm pcm_rec[2]; /* PCM information */
173
174 /* dynamic controls and input_mux */
175 struct auto_pin_cfg autocfg;
176 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100177 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200178 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200179 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100180 struct hda_input_mux private_mono_mux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100181
182 /* virtual master */
183 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200184};
185
186static hda_nid_t stac9200_adc_nids[1] = {
187 0x03,
188};
189
190static hda_nid_t stac9200_mux_nids[1] = {
191 0x0c,
192};
193
194static hda_nid_t stac9200_dac_nids[1] = {
195 0x02,
196};
197
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100198static hda_nid_t stac92hd73xx_pwr_nids[8] = {
199 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
200 0x0f, 0x10, 0x11
201};
202
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100203static hda_nid_t stac92hd73xx_adc_nids[2] = {
204 0x1a, 0x1b
205};
206
207#define STAC92HD73XX_NUM_DMICS 2
208static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
209 0x13, 0x14, 0
210};
211
212#define STAC92HD73_DAC_COUNT 5
213static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
214 0x15, 0x16, 0x17, 0x18, 0x19,
215};
216
217static hda_nid_t stac92hd73xx_mux_nids[4] = {
218 0x28, 0x29, 0x2a, 0x2b,
219};
220
221static hda_nid_t stac92hd73xx_dmux_nids[2] = {
222 0x20, 0x21,
223};
224
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100225static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
226 0x0a, 0x0d, 0x0f
227};
228
Matthew Ranostaye035b842007-11-06 11:53:55 +0100229static hda_nid_t stac92hd71bxx_adc_nids[2] = {
230 0x12, 0x13,
231};
232
233static hda_nid_t stac92hd71bxx_mux_nids[2] = {
234 0x1a, 0x1b
235};
236
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100237static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
238 0x1c,
239};
240
Matthew Ranostaye035b842007-11-06 11:53:55 +0100241static hda_nid_t stac92hd71bxx_dac_nids[2] = {
242 0x10, /*0x11, */
243};
244
245#define STAC92HD71BXX_NUM_DMICS 2
246static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
247 0x18, 0x19, 0
248};
249
Tobin Davis8e21c342007-01-08 11:04:17 +0100250static hda_nid_t stac925x_adc_nids[1] = {
251 0x03,
252};
253
254static hda_nid_t stac925x_mux_nids[1] = {
255 0x0f,
256};
257
258static hda_nid_t stac925x_dac_nids[1] = {
259 0x02,
260};
261
Takashi Iwaif6e98522007-10-16 14:27:04 +0200262#define STAC925X_NUM_DMICS 1
263static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
264 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200265};
266
Takashi Iwai1697055e2007-12-18 18:05:52 +0100267static hda_nid_t stac925x_dmux_nids[1] = {
268 0x14,
269};
270
Matt2f2f4252005-04-13 14:45:30 +0200271static hda_nid_t stac922x_adc_nids[2] = {
272 0x06, 0x07,
273};
274
275static hda_nid_t stac922x_mux_nids[2] = {
276 0x12, 0x13,
277};
278
Matt Porter3cc08dc2006-01-23 15:27:49 +0100279static hda_nid_t stac927x_adc_nids[3] = {
280 0x07, 0x08, 0x09
281};
282
283static hda_nid_t stac927x_mux_nids[3] = {
284 0x15, 0x16, 0x17
285};
286
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100287static hda_nid_t stac927x_dmux_nids[1] = {
288 0x1b,
289};
290
Matthew Ranostay7f168592007-10-18 17:38:17 +0200291#define STAC927X_NUM_DMICS 2
292static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
293 0x13, 0x14, 0
294};
295
Matt Porterf3302a52006-07-31 12:49:34 +0200296static hda_nid_t stac9205_adc_nids[2] = {
297 0x12, 0x13
298};
299
300static hda_nid_t stac9205_mux_nids[2] = {
301 0x19, 0x1a
302};
303
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100304static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100305 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100306};
307
Takashi Iwaif6e98522007-10-16 14:27:04 +0200308#define STAC9205_NUM_DMICS 2
309static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
310 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200311};
312
Mattc7d4b2f2005-06-27 14:59:41 +0200313static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200314 0x08, 0x09, 0x0d, 0x0e,
315 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200316};
317
Tobin Davis8e21c342007-01-08 11:04:17 +0100318static hda_nid_t stac925x_pin_nids[8] = {
319 0x07, 0x08, 0x0a, 0x0b,
320 0x0c, 0x0d, 0x10, 0x11,
321};
322
Matt2f2f4252005-04-13 14:45:30 +0200323static hda_nid_t stac922x_pin_nids[10] = {
324 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
325 0x0f, 0x10, 0x11, 0x15, 0x1b,
326};
327
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100328static hda_nid_t stac92hd73xx_pin_nids[12] = {
329 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
330 0x0f, 0x10, 0x11, 0x12, 0x13,
331 0x14, 0x22
332};
333
Matthew Ranostaye035b842007-11-06 11:53:55 +0100334static hda_nid_t stac92hd71bxx_pin_nids[10] = {
335 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
336 0x0f, 0x14, 0x18, 0x19, 0x1e,
337};
338
Matt Porter3cc08dc2006-01-23 15:27:49 +0100339static hda_nid_t stac927x_pin_nids[14] = {
340 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
341 0x0f, 0x10, 0x11, 0x12, 0x13,
342 0x14, 0x21, 0x22, 0x23,
343};
344
Matt Porterf3302a52006-07-31 12:49:34 +0200345static hda_nid_t stac9205_pin_nids[12] = {
346 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
347 0x0f, 0x14, 0x16, 0x17, 0x18,
348 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200349};
350
Matt Porter8b657272006-10-26 17:12:59 +0200351static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
352 struct snd_ctl_elem_info *uinfo)
353{
354 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
355 struct sigmatel_spec *spec = codec->spec;
356 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
357}
358
359static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
360 struct snd_ctl_elem_value *ucontrol)
361{
362 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
363 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100364 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200365
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100366 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200367 return 0;
368}
369
370static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
371 struct snd_ctl_elem_value *ucontrol)
372{
373 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
374 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100375 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200376
377 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100378 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200379}
380
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100381static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200382{
383 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
384 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200385 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200386}
387
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100388static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200389{
390 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
391 struct sigmatel_spec *spec = codec->spec;
392 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
393
394 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
395 return 0;
396}
397
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100398static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200399{
400 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
401 struct sigmatel_spec *spec = codec->spec;
402 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
403
Mattc7d4b2f2005-06-27 14:59:41 +0200404 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200405 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
406}
407
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100408static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
409 struct snd_ctl_elem_info *uinfo)
410{
411 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
412 struct sigmatel_spec *spec = codec->spec;
413 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
414}
415
416static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
417 struct snd_ctl_elem_value *ucontrol)
418{
419 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
420 struct sigmatel_spec *spec = codec->spec;
421
422 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
423 return 0;
424}
425
426static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
427 struct snd_ctl_elem_value *ucontrol)
428{
429 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
430 struct sigmatel_spec *spec = codec->spec;
431
432 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
433 spec->mono_nid, &spec->cur_mmux);
434}
435
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200436#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
437
438static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_value *ucontrol)
440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100442 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200443 struct sigmatel_spec *spec = codec->spec;
444
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100445 ucontrol->value.integer.value[0] = !!(spec->aloopback &
446 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200447 return 0;
448}
449
450static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
451 struct snd_ctl_elem_value *ucontrol)
452{
453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
454 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100455 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200456 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100457 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200458
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100459 idx_val = spec->aloopback_mask << idx;
460 if (ucontrol->value.integer.value[0])
461 val = spec->aloopback | idx_val;
462 else
463 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100464 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200465 return 0;
466
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100467 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200468
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100469 /* Only return the bits defined by the shift value of the
470 * first two bytes of the mask
471 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200472 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100473 kcontrol->private_value & 0xFFFF, 0x0);
474 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200475
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100476 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200477 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100478 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200479 } else {
480 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100481 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200482 }
483
484 snd_hda_codec_write_cache(codec, codec->afg, 0,
485 kcontrol->private_value >> 16, dac_mode);
486
487 return 1;
488}
489
Mattc7d4b2f2005-06-27 14:59:41 +0200490static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200491 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200492 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200493 {}
494};
495
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200496static struct hda_verb stac9200_eapd_init[] = {
497 /* set dac0mux for dac converter */
498 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
499 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
500 {}
501};
502
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100503static struct hda_verb stac92hd73xx_6ch_core_init[] = {
504 /* set master volume and direct control */
505 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
506 /* setup audio connections */
507 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
508 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
509 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
510 /* setup adcs to point to mixer */
511 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
512 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100513 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
514 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
515 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
516 /* setup import muxs */
517 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
518 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
519 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
520 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
521 {}
522};
523
524static struct hda_verb stac92hd73xx_8ch_core_init[] = {
525 /* set master volume and direct control */
526 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
527 /* setup audio connections */
528 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
529 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
530 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
531 /* connect hp ports to dac3 */
532 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
533 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
534 /* setup adcs to point to mixer */
535 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
536 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100537 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
538 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
539 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
540 /* setup import muxs */
541 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
542 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
543 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
544 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
545 {}
546};
547
548static struct hda_verb stac92hd73xx_10ch_core_init[] = {
549 /* set master volume and direct control */
550 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
551 /* setup audio connections */
552 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
553 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
554 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
555 /* dac3 is connected to import3 mux */
556 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
557 /* connect hp ports to dac4 */
558 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
559 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
560 /* setup adcs to point to mixer */
561 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
562 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100563 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
564 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
565 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
566 /* setup import muxs */
567 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
568 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
569 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
570 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
571 {}
572};
573
Matthew Ranostaye035b842007-11-06 11:53:55 +0100574static struct hda_verb stac92hd71bxx_core_init[] = {
575 /* set master volume and direct control */
576 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
577 /* connect headphone jack to dac1 */
578 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100579 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
580 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
581 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
582 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
583 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100584};
585
586static struct hda_verb stac92hd71bxx_analog_core_init[] = {
587 /* set master volume and direct control */
588 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
589 /* connect headphone jack to dac1 */
590 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100591 /* connect ports 0d and 0f to audio mixer */
592 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
593 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100594 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100595 /* unmute dac0 input in audio mixer */
596 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100597 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
598 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
599 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
600 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100601 {}
602};
603
Tobin Davis8e21c342007-01-08 11:04:17 +0100604static struct hda_verb stac925x_core_init[] = {
605 /* set dac0mux for dac converter */
606 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
607 {}
608};
609
Mattc7d4b2f2005-06-27 14:59:41 +0200610static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200611 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200612 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200613 {}
614};
615
Tobin Davis93ed1502006-09-01 21:03:12 +0200616static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200617 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200618 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200619 /* unmute node 0x1b */
620 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
621 /* select node 0x03 as DAC */
622 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
623 {}
624};
625
Matt Porter3cc08dc2006-01-23 15:27:49 +0100626static struct hda_verb stac927x_core_init[] = {
627 /* set master volume and direct control */
628 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
629 {}
630};
631
Matt Porterf3302a52006-07-31 12:49:34 +0200632static struct hda_verb stac9205_core_init[] = {
633 /* set master volume and direct control */
634 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
635 {}
636};
637
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100638#define STAC_MONO_MUX \
639 { \
640 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
641 .name = "Mono Mux", \
642 .count = 1, \
643 .info = stac92xx_mono_mux_enum_info, \
644 .get = stac92xx_mono_mux_enum_get, \
645 .put = stac92xx_mono_mux_enum_put, \
646 }
647
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200648#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200649 { \
650 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
651 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200652 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200653 .info = stac92xx_mux_enum_info, \
654 .get = stac92xx_mux_enum_get, \
655 .put = stac92xx_mux_enum_put, \
656 }
657
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100658#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200659 { \
660 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
661 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100662 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200663 .info = stac92xx_aloopback_info, \
664 .get = stac92xx_aloopback_get, \
665 .put = stac92xx_aloopback_put, \
666 .private_value = verb_read | (verb_write << 16), \
667 }
668
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100669static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200670 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
671 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200672 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200673 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
674 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200675 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200676 { } /* end */
677};
678
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100679static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100680 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
681
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100682 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
683 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
684
685 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
686 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
687
688 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
689 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
690
691 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
692 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
693
694 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
695 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
696
697 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
698 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
699
700 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
701 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
702 { } /* end */
703};
704
705static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100706 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
707
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100708 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
709 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
710
711 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
712 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
713
714 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
715 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
716
717 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
718 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
719
720 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
721 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
722
723 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
724 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
725
726 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
727 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
728 { } /* end */
729};
730
731static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
733
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100734 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
735 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
736
737 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
738 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
739
740 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
741 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
742
743 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
744 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
745
746 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
747 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
748
749 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
750 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
751
752 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
753 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
754 { } /* end */
755};
756
Matthew Ranostay541eee82007-12-14 12:08:04 +0100757static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100758 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100759
Matthew Ranostay9b359472007-11-07 13:03:12 +0100760 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
761 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
762 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
763
764 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
765 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
766 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
767
768 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
769 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100770 { } /* end */
771};
772
Matthew Ranostay541eee82007-12-14 12:08:04 +0100773static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100774 STAC_INPUT_SOURCE(2),
775 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
776
Matthew Ranostay541eee82007-12-14 12:08:04 +0100777 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
778 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
779 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
780
781 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
782 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
783 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
784 { } /* end */
785};
786
Tobin Davis8e21c342007-01-08 11:04:17 +0100787static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200788 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100789 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
790 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
791 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
792 { } /* end */
793};
794
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100795static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200796 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100797 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200798
799 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
800 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
801 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
802
803 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
804 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
805 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
806
807 { } /* end */
808};
809
810/* This needs to be generated dynamically based on sequence */
811static struct snd_kcontrol_new stac922x_mixer[] = {
812 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200813 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
814 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
815 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
816
817 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
818 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
819 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
820 { } /* end */
821};
822
823
824static struct snd_kcontrol_new stac927x_mixer[] = {
825 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100826 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200827
828 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
829 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
830 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
831
832 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
833 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
834 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
835
836 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
837 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
838 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200839 { } /* end */
840};
841
Takashi Iwai1697055e2007-12-18 18:05:52 +0100842static struct snd_kcontrol_new stac_dmux_mixer = {
843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
844 .name = "Digital Input Source",
845 /* count set later */
846 .info = stac92xx_dmux_enum_info,
847 .get = stac92xx_dmux_enum_get,
848 .put = stac92xx_dmux_enum_put,
849};
850
Takashi Iwai2134ea42008-01-10 16:53:55 +0100851static const char *slave_vols[] = {
852 "Front Playback Volume",
853 "Surround Playback Volume",
854 "Center Playback Volume",
855 "LFE Playback Volume",
856 "Side Playback Volume",
857 "Headphone Playback Volume",
858 "Headphone Playback Volume",
859 "Speaker Playback Volume",
860 "External Speaker Playback Volume",
861 "Speaker2 Playback Volume",
862 NULL
863};
864
865static const char *slave_sws[] = {
866 "Front Playback Switch",
867 "Surround Playback Switch",
868 "Center Playback Switch",
869 "LFE Playback Switch",
870 "Side Playback Switch",
871 "Headphone Playback Switch",
872 "Headphone Playback Switch",
873 "Speaker Playback Switch",
874 "External Speaker Playback Switch",
875 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100876 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100877 NULL
878};
879
Matt2f2f4252005-04-13 14:45:30 +0200880static int stac92xx_build_controls(struct hda_codec *codec)
881{
882 struct sigmatel_spec *spec = codec->spec;
883 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200884 int i;
Matt2f2f4252005-04-13 14:45:30 +0200885
886 err = snd_hda_add_new_ctls(codec, spec->mixer);
887 if (err < 0)
888 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200889
890 for (i = 0; i < spec->num_mixers; i++) {
891 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
892 if (err < 0)
893 return err;
894 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100895 if (spec->num_dmuxes > 0) {
896 stac_dmux_mixer.count = spec->num_dmuxes;
897 err = snd_ctl_add(codec->bus->card,
898 snd_ctl_new1(&stac_dmux_mixer, codec));
899 if (err < 0)
900 return err;
901 }
Mattc7d4b2f2005-06-27 14:59:41 +0200902
Mattdabbed62005-06-14 10:19:34 +0200903 if (spec->multiout.dig_out_nid) {
904 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
905 if (err < 0)
906 return err;
907 }
908 if (spec->dig_in_nid) {
909 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
910 if (err < 0)
911 return err;
912 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100913
914 /* if we have no master control, let's create it */
915 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
916 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
917 HDA_OUTPUT, spec->vmaster_tlv);
918 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
919 spec->vmaster_tlv, slave_vols);
920 if (err < 0)
921 return err;
922 }
923 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
924 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
925 NULL, slave_sws);
926 if (err < 0)
927 return err;
928 }
929
Mattdabbed62005-06-14 10:19:34 +0200930 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200931}
932
Matt Porter403d1942005-11-29 15:00:51 +0100933static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200934 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200935 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
936};
937
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200938/*
939 STAC 9200 pin configs for
940 102801A8
941 102801DE
942 102801E8
943*/
944static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200945 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
946 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200947};
948
949/*
950 STAC 9200 pin configs for
951 102801C0
952 102801C1
953*/
954static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200955 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
956 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200957};
958
959/*
960 STAC 9200 pin configs for
961 102801C4 (Dell Dimension E310)
962 102801C5
963 102801C7
964 102801D9
965 102801DA
966 102801E3
967*/
968static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200969 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
970 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200971};
972
973
974/*
975 STAC 9200-32 pin configs for
976 102801B5 (Dell Inspiron 630m)
977 102801D8 (Dell Inspiron 640m)
978*/
979static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200980 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
981 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200982};
983
984/*
985 STAC 9200-32 pin configs for
986 102801C2 (Dell Latitude D620)
987 102801C8
988 102801CC (Dell Latitude D820)
989 102801D4
990 102801D6
991*/
992static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200993 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
994 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200995};
996
997/*
998 STAC 9200-32 pin configs for
999 102801CE (Dell XPS M1710)
1000 102801CF (Dell Precision M90)
1001*/
1002static unsigned int dell9200_m23_pin_configs[8] = {
1003 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1004 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1005};
1006
1007/*
1008 STAC 9200-32 pin configs for
1009 102801C9
1010 102801CA
1011 102801CB (Dell Latitude 120L)
1012 102801D3
1013*/
1014static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001015 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1016 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001017};
1018
1019/*
1020 STAC 9200-32 pin configs for
1021 102801BD (Dell Inspiron E1505n)
1022 102801EE
1023 102801EF
1024*/
1025static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001026 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1027 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001028};
1029
1030/*
1031 STAC 9200-32 pin configs for
1032 102801F5 (Dell Inspiron 1501)
1033 102801F6
1034*/
1035static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001036 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1037 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001038};
1039
1040/*
1041 STAC 9200-32
1042 102801CD (Dell Inspiron E1705/9400)
1043*/
1044static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001045 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1046 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001047};
1048
1049
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001050static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1051 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001052 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1053 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1054 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1055 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1056 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1057 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1058 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1059 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1060 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1061 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001062};
1063
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001064static const char *stac9200_models[STAC_9200_MODELS] = {
1065 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001066 [STAC_9200_DELL_D21] = "dell-d21",
1067 [STAC_9200_DELL_D22] = "dell-d22",
1068 [STAC_9200_DELL_D23] = "dell-d23",
1069 [STAC_9200_DELL_M21] = "dell-m21",
1070 [STAC_9200_DELL_M22] = "dell-m22",
1071 [STAC_9200_DELL_M23] = "dell-m23",
1072 [STAC_9200_DELL_M24] = "dell-m24",
1073 [STAC_9200_DELL_M25] = "dell-m25",
1074 [STAC_9200_DELL_M26] = "dell-m26",
1075 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001076 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001077};
1078
1079static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1080 /* SigmaTel reference board */
1081 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1082 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001083 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001084 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1085 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001086 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001087 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1088 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1089 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1090 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1091 "unknown Dell", STAC_9200_DELL_D22),
1092 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1093 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001094 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001095 "Dell Latitude D620", STAC_9200_DELL_M22),
1096 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1097 "unknown Dell", STAC_9200_DELL_D23),
1098 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1099 "unknown Dell", STAC_9200_DELL_D23),
1100 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1101 "unknown Dell", STAC_9200_DELL_M22),
1102 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1103 "unknown Dell", STAC_9200_DELL_M24),
1104 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1105 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001106 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001107 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001108 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001109 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001110 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001111 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001112 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001113 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001114 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001115 "Dell Precision M90", STAC_9200_DELL_M23),
1116 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1117 "unknown Dell", STAC_9200_DELL_M22),
1118 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1119 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001120 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001121 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001122 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001123 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1124 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1125 "unknown Dell", STAC_9200_DELL_D23),
1126 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1127 "unknown Dell", STAC_9200_DELL_D23),
1128 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1129 "unknown Dell", STAC_9200_DELL_D21),
1130 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1131 "unknown Dell", STAC_9200_DELL_D23),
1132 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1133 "unknown Dell", STAC_9200_DELL_D21),
1134 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1135 "unknown Dell", STAC_9200_DELL_M25),
1136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1137 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001139 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1141 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001142 /* Panasonic */
1143 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001144 /* Gateway machines needs EAPD to be set on resume */
1145 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1146 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1147 STAC_9200_GATEWAY),
1148 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1149 STAC_9200_GATEWAY),
Matt Porter403d1942005-11-29 15:00:51 +01001150 {} /* terminator */
1151};
1152
Tobin Davis8e21c342007-01-08 11:04:17 +01001153static unsigned int ref925x_pin_configs[8] = {
1154 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001155 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001156};
1157
1158static unsigned int stac925x_MA6_pin_configs[8] = {
1159 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1160 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1161};
1162
Tobin Davis2c11f952007-05-17 09:36:34 +02001163static unsigned int stac925x_PA6_pin_configs[8] = {
1164 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1165 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1166};
1167
Tobin Davis8e21c342007-01-08 11:04:17 +01001168static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001169 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1170 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001171};
1172
1173static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1174 [STAC_REF] = ref925x_pin_configs,
1175 [STAC_M2_2] = stac925xM2_2_pin_configs,
1176 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001177 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001178};
1179
1180static const char *stac925x_models[STAC_925x_MODELS] = {
1181 [STAC_REF] = "ref",
1182 [STAC_M2_2] = "m2-2",
1183 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001184 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001185};
1186
1187static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1188 /* SigmaTel reference board */
1189 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001190 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001191 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1192 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1193 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001194 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001195 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1196 {} /* terminator */
1197};
1198
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001199static unsigned int ref92hd73xx_pin_configs[12] = {
1200 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1201 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1202 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1203};
1204
1205static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1206 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1207};
1208
1209static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1210 [STAC_92HD73XX_REF] = "ref",
1211};
1212
1213static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1214 /* SigmaTel reference board */
1215 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1216 "DFI LanParty", STAC_92HD73XX_REF),
1217 {} /* terminator */
1218};
1219
Matthew Ranostaye035b842007-11-06 11:53:55 +01001220static unsigned int ref92hd71bxx_pin_configs[10] = {
1221 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001222 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001223 0x90a000f0, 0x01452050,
1224};
1225
1226static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1227 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1228};
1229
1230static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1231 [STAC_92HD71BXX_REF] = "ref",
1232};
1233
1234static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1235 /* SigmaTel reference board */
1236 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1237 "DFI LanParty", STAC_92HD71BXX_REF),
1238 {} /* terminator */
1239};
1240
Matt Porter403d1942005-11-29 15:00:51 +01001241static unsigned int ref922x_pin_configs[10] = {
1242 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1243 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001244 0x40000100, 0x40000100,
1245};
1246
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001247/*
1248 STAC 922X pin configs for
1249 102801A7
1250 102801AB
1251 102801A9
1252 102801D1
1253 102801D2
1254*/
1255static unsigned int dell_922x_d81_pin_configs[10] = {
1256 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1257 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1258 0x01813122, 0x400001f2,
1259};
1260
1261/*
1262 STAC 922X pin configs for
1263 102801AC
1264 102801D0
1265*/
1266static unsigned int dell_922x_d82_pin_configs[10] = {
1267 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1268 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1269 0x01813122, 0x400001f1,
1270};
1271
1272/*
1273 STAC 922X pin configs for
1274 102801BF
1275*/
1276static unsigned int dell_922x_m81_pin_configs[10] = {
1277 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1278 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1279 0x40C003f1, 0x405003f0,
1280};
1281
1282/*
1283 STAC 9221 A1 pin configs for
1284 102801D7 (Dell XPS M1210)
1285*/
1286static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001287 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1288 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001289 0x508003f3, 0x405003f4,
1290};
1291
Matt Porter403d1942005-11-29 15:00:51 +01001292static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001293 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001294 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1295 0x02a19120, 0x40000100,
1296};
1297
1298static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001299 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1300 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001301 0x02a19320, 0x40000100,
1302};
1303
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001304static unsigned int intel_mac_v1_pin_configs[10] = {
1305 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1306 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001307 0x400000fc, 0x400000fb,
1308};
1309
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001310static unsigned int intel_mac_v2_pin_configs[10] = {
1311 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1312 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001313 0x400000fc, 0x400000fb,
1314};
1315
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001316static unsigned int intel_mac_v3_pin_configs[10] = {
1317 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1318 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1319 0x400000fc, 0x400000fb,
1320};
1321
1322static unsigned int intel_mac_v4_pin_configs[10] = {
1323 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1324 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1325 0x400000fc, 0x400000fb,
1326};
1327
1328static unsigned int intel_mac_v5_pin_configs[10] = {
1329 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1330 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1331 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001332};
1333
Takashi Iwai76c08822007-06-19 12:17:42 +02001334
Takashi Iwai19039bd2006-06-28 15:52:16 +02001335static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001336 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001337 [STAC_D945GTP3] = d945gtp3_pin_configs,
1338 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001339 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1340 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1341 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1342 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1343 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001344 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001345 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1346 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1347 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1348 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1349 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1350 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001351 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1352 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1353 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1354 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001355};
1356
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001357static const char *stac922x_models[STAC_922X_MODELS] = {
1358 [STAC_D945_REF] = "ref",
1359 [STAC_D945GTP5] = "5stack",
1360 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001361 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1362 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1363 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1364 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1365 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001366 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001367 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001368 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001369 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1370 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001371 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001372 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001373 [STAC_922X_DELL_D81] = "dell-d81",
1374 [STAC_922X_DELL_D82] = "dell-d82",
1375 [STAC_922X_DELL_M81] = "dell-m81",
1376 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001377};
1378
1379static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1380 /* SigmaTel reference board */
1381 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1382 "DFI LanParty", STAC_D945_REF),
1383 /* Intel 945G based systems */
1384 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1385 "Intel D945G", STAC_D945GTP3),
1386 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1387 "Intel D945G", STAC_D945GTP3),
1388 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1389 "Intel D945G", STAC_D945GTP3),
1390 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1391 "Intel D945G", STAC_D945GTP3),
1392 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1393 "Intel D945G", STAC_D945GTP3),
1394 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1395 "Intel D945G", STAC_D945GTP3),
1396 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1397 "Intel D945G", STAC_D945GTP3),
1398 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1399 "Intel D945G", STAC_D945GTP3),
1400 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1401 "Intel D945G", STAC_D945GTP3),
1402 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1403 "Intel D945G", STAC_D945GTP3),
1404 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1405 "Intel D945G", STAC_D945GTP3),
1406 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1407 "Intel D945G", STAC_D945GTP3),
1408 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1409 "Intel D945G", STAC_D945GTP3),
1410 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1411 "Intel D945G", STAC_D945GTP3),
1412 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1413 "Intel D945G", STAC_D945GTP3),
1414 /* Intel D945G 5-stack systems */
1415 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1416 "Intel D945G", STAC_D945GTP5),
1417 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1418 "Intel D945G", STAC_D945GTP5),
1419 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1420 "Intel D945G", STAC_D945GTP5),
1421 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1422 "Intel D945G", STAC_D945GTP5),
1423 /* Intel 945P based systems */
1424 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1425 "Intel D945P", STAC_D945GTP3),
1426 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1427 "Intel D945P", STAC_D945GTP3),
1428 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1429 "Intel D945P", STAC_D945GTP3),
1430 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1431 "Intel D945P", STAC_D945GTP3),
1432 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1433 "Intel D945P", STAC_D945GTP3),
1434 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1435 "Intel D945P", STAC_D945GTP5),
1436 /* other systems */
1437 /* Apple Mac Mini (early 2006) */
1438 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001439 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001440 /* Dell systems */
1441 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1442 "unknown Dell", STAC_922X_DELL_D81),
1443 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1444 "unknown Dell", STAC_922X_DELL_D81),
1445 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1446 "unknown Dell", STAC_922X_DELL_D81),
1447 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1448 "unknown Dell", STAC_922X_DELL_D82),
1449 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1450 "unknown Dell", STAC_922X_DELL_M81),
1451 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1452 "unknown Dell", STAC_922X_DELL_D82),
1453 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1454 "unknown Dell", STAC_922X_DELL_D81),
1455 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1456 "unknown Dell", STAC_922X_DELL_D81),
1457 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1458 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001459 {} /* terminator */
1460};
1461
Matt Porter3cc08dc2006-01-23 15:27:49 +01001462static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001463 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1464 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1465 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1466 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001467};
1468
Tobin Davis93ed1502006-09-01 21:03:12 +02001469static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001470 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1471 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1472 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1473 0x40000100, 0x40000100
1474};
1475
Tobin Davis93ed1502006-09-01 21:03:12 +02001476static unsigned int d965_5st_pin_configs[14] = {
1477 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1478 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1479 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1480 0x40000100, 0x40000100
1481};
1482
Tobin Davis4ff076e2007-08-07 11:48:12 +02001483static unsigned int dell_3st_pin_configs[14] = {
1484 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1485 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001486 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001487 0x40c003fc, 0x40000100
1488};
1489
Tobin Davis93ed1502006-09-01 21:03:12 +02001490static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001491 [STAC_D965_REF] = ref927x_pin_configs,
1492 [STAC_D965_3ST] = d965_3st_pin_configs,
1493 [STAC_D965_5ST] = d965_5st_pin_configs,
1494 [STAC_DELL_3ST] = dell_3st_pin_configs,
1495 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001496};
1497
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001498static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001499 [STAC_D965_REF] = "ref",
1500 [STAC_D965_3ST] = "3stack",
1501 [STAC_D965_5ST] = "5stack",
1502 [STAC_DELL_3ST] = "dell-3stack",
1503 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001504};
1505
1506static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1507 /* SigmaTel reference board */
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1509 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001510 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001511 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001513 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001514 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1516 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1518 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1520 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1521 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1522 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1524 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001530 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001531 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001532 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001533 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001535 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001536 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001544 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001554 {} /* terminator */
1555};
1556
Matt Porterf3302a52006-07-31 12:49:34 +02001557static unsigned int ref9205_pin_configs[12] = {
1558 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001559 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001560 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001561};
1562
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001563/*
1564 STAC 9205 pin configs for
1565 102801F1
1566 102801F2
1567 102801FC
1568 102801FD
1569 10280204
1570 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001571 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001572*/
1573static unsigned int dell_9205_m42_pin_configs[12] = {
1574 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1575 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1576 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1577};
1578
1579/*
1580 STAC 9205 pin configs for
1581 102801F9
1582 102801FA
1583 102801FE
1584 102801FF (Dell Precision M4300)
1585 10280206
1586 10280200
1587 10280201
1588*/
1589static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001590 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1591 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1592 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1593};
1594
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001595static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001596 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1597 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1598 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1599};
1600
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001601static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001602 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001603 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1604 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1605 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001606};
1607
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001608static const char *stac9205_models[STAC_9205_MODELS] = {
1609 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001610 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001611 [STAC_9205_DELL_M43] = "dell-m43",
1612 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001613};
1614
1615static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1616 /* SigmaTel reference board */
1617 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1618 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001619 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1620 "unknown Dell", STAC_9205_DELL_M42),
1621 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1622 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001623 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001624 "Dell Precision", STAC_9205_DELL_M43),
1625 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1626 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001627 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1628 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001629 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1630 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001631 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1632 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001633 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1634 "unknown Dell", STAC_9205_DELL_M42),
1635 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1636 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001637 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1638 "Dell Precision", STAC_9205_DELL_M43),
1639 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001640 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001641 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1642 "Dell Precision", STAC_9205_DELL_M43),
1643 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1644 "Dell Inspiron", STAC_9205_DELL_M44),
1645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1646 "Dell Inspiron", STAC_9205_DELL_M44),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1648 "Dell Inspiron", STAC_9205_DELL_M44),
1649 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1650 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001651 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1652 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001653 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1654 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001655 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1656 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001657 {} /* terminator */
1658};
1659
Richard Fish11b44bb2006-08-23 18:31:34 +02001660static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1661{
1662 int i;
1663 struct sigmatel_spec *spec = codec->spec;
1664
1665 if (! spec->bios_pin_configs) {
1666 spec->bios_pin_configs = kcalloc(spec->num_pins,
1667 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1668 if (! spec->bios_pin_configs)
1669 return -ENOMEM;
1670 }
1671
1672 for (i = 0; i < spec->num_pins; i++) {
1673 hda_nid_t nid = spec->pin_nids[i];
1674 unsigned int pin_cfg;
1675
1676 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1677 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1678 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1679 nid, pin_cfg);
1680 spec->bios_pin_configs[i] = pin_cfg;
1681 }
1682
1683 return 0;
1684}
1685
Matthew Ranostay87d48362007-07-17 11:52:24 +02001686static void stac92xx_set_config_reg(struct hda_codec *codec,
1687 hda_nid_t pin_nid, unsigned int pin_config)
1688{
1689 int i;
1690 snd_hda_codec_write(codec, pin_nid, 0,
1691 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1692 pin_config & 0x000000ff);
1693 snd_hda_codec_write(codec, pin_nid, 0,
1694 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1695 (pin_config & 0x0000ff00) >> 8);
1696 snd_hda_codec_write(codec, pin_nid, 0,
1697 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1698 (pin_config & 0x00ff0000) >> 16);
1699 snd_hda_codec_write(codec, pin_nid, 0,
1700 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1701 pin_config >> 24);
1702 i = snd_hda_codec_read(codec, pin_nid, 0,
1703 AC_VERB_GET_CONFIG_DEFAULT,
1704 0x00);
1705 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1706 pin_nid, i);
1707}
1708
Matt2f2f4252005-04-13 14:45:30 +02001709static void stac92xx_set_config_regs(struct hda_codec *codec)
1710{
1711 int i;
1712 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001713
Matthew Ranostay87d48362007-07-17 11:52:24 +02001714 if (!spec->pin_configs)
1715 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001716
Matthew Ranostay87d48362007-07-17 11:52:24 +02001717 for (i = 0; i < spec->num_pins; i++)
1718 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1719 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001720}
Matt2f2f4252005-04-13 14:45:30 +02001721
Matt2f2f4252005-04-13 14:45:30 +02001722/*
1723 * Analog playback callbacks
1724 */
1725static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1726 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001727 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001728{
1729 struct sigmatel_spec *spec = codec->spec;
1730 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1731}
1732
1733static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1734 struct hda_codec *codec,
1735 unsigned int stream_tag,
1736 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001737 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001738{
1739 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001740 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001741}
1742
1743static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1744 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001745 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001746{
1747 struct sigmatel_spec *spec = codec->spec;
1748 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1749}
1750
1751/*
Mattdabbed62005-06-14 10:19:34 +02001752 * Digital playback callbacks
1753 */
1754static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1755 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001756 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001757{
1758 struct sigmatel_spec *spec = codec->spec;
1759 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1760}
1761
1762static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1763 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001764 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001765{
1766 struct sigmatel_spec *spec = codec->spec;
1767 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1768}
1769
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001770static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1771 struct hda_codec *codec,
1772 unsigned int stream_tag,
1773 unsigned int format,
1774 struct snd_pcm_substream *substream)
1775{
1776 struct sigmatel_spec *spec = codec->spec;
1777 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1778 stream_tag, format, substream);
1779}
1780
Mattdabbed62005-06-14 10:19:34 +02001781
1782/*
Matt2f2f4252005-04-13 14:45:30 +02001783 * Analog capture callbacks
1784 */
1785static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1786 struct hda_codec *codec,
1787 unsigned int stream_tag,
1788 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001789 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001790{
1791 struct sigmatel_spec *spec = codec->spec;
1792
1793 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1794 stream_tag, 0, format);
1795 return 0;
1796}
1797
1798static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1799 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001800 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001801{
1802 struct sigmatel_spec *spec = codec->spec;
1803
1804 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1805 return 0;
1806}
1807
Mattdabbed62005-06-14 10:19:34 +02001808static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1809 .substreams = 1,
1810 .channels_min = 2,
1811 .channels_max = 2,
1812 /* NID is set in stac92xx_build_pcms */
1813 .ops = {
1814 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001815 .close = stac92xx_dig_playback_pcm_close,
1816 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001817 },
1818};
1819
1820static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1821 .substreams = 1,
1822 .channels_min = 2,
1823 .channels_max = 2,
1824 /* NID is set in stac92xx_build_pcms */
1825};
1826
Matt2f2f4252005-04-13 14:45:30 +02001827static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1828 .substreams = 1,
1829 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001830 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001831 .nid = 0x02, /* NID to query formats and rates */
1832 .ops = {
1833 .open = stac92xx_playback_pcm_open,
1834 .prepare = stac92xx_playback_pcm_prepare,
1835 .cleanup = stac92xx_playback_pcm_cleanup
1836 },
1837};
1838
Matt Porter3cc08dc2006-01-23 15:27:49 +01001839static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1840 .substreams = 1,
1841 .channels_min = 2,
1842 .channels_max = 2,
1843 .nid = 0x06, /* NID to query formats and rates */
1844 .ops = {
1845 .open = stac92xx_playback_pcm_open,
1846 .prepare = stac92xx_playback_pcm_prepare,
1847 .cleanup = stac92xx_playback_pcm_cleanup
1848 },
1849};
1850
Matt2f2f4252005-04-13 14:45:30 +02001851static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001852 .channels_min = 2,
1853 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001854 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001855 .ops = {
1856 .prepare = stac92xx_capture_pcm_prepare,
1857 .cleanup = stac92xx_capture_pcm_cleanup
1858 },
1859};
1860
1861static int stac92xx_build_pcms(struct hda_codec *codec)
1862{
1863 struct sigmatel_spec *spec = codec->spec;
1864 struct hda_pcm *info = spec->pcm_rec;
1865
1866 codec->num_pcms = 1;
1867 codec->pcm_info = info;
1868
Mattc7d4b2f2005-06-27 14:59:41 +02001869 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001870 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001871 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001872 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001873 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001874
1875 if (spec->alt_switch) {
1876 codec->num_pcms++;
1877 info++;
1878 info->name = "STAC92xx Analog Alt";
1879 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1880 }
Matt2f2f4252005-04-13 14:45:30 +02001881
Mattdabbed62005-06-14 10:19:34 +02001882 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1883 codec->num_pcms++;
1884 info++;
1885 info->name = "STAC92xx Digital";
1886 if (spec->multiout.dig_out_nid) {
1887 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1888 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1889 }
1890 if (spec->dig_in_nid) {
1891 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1892 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1893 }
1894 }
1895
Matt2f2f4252005-04-13 14:45:30 +02001896 return 0;
1897}
1898
Takashi Iwaic960a032006-03-23 17:06:28 +01001899static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1900{
1901 unsigned int pincap = snd_hda_param_read(codec, nid,
1902 AC_PAR_PIN_CAP);
1903 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1904 if (pincap & AC_PINCAP_VREF_100)
1905 return AC_PINCTL_VREF_100;
1906 if (pincap & AC_PINCAP_VREF_80)
1907 return AC_PINCTL_VREF_80;
1908 if (pincap & AC_PINCAP_VREF_50)
1909 return AC_PINCTL_VREF_50;
1910 if (pincap & AC_PINCAP_VREF_GRD)
1911 return AC_PINCTL_VREF_GRD;
1912 return 0;
1913}
1914
Matt Porter403d1942005-11-29 15:00:51 +01001915static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1916
1917{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001918 snd_hda_codec_write_cache(codec, nid, 0,
1919 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001920}
1921
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001922#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001923
1924static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1925{
1926 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1927 struct sigmatel_spec *spec = codec->spec;
1928 int io_idx = kcontrol-> private_value & 0xff;
1929
1930 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1931 return 0;
1932}
1933
1934static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1935{
1936 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1937 struct sigmatel_spec *spec = codec->spec;
1938 hda_nid_t nid = kcontrol->private_value >> 8;
1939 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001940 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001941
1942 spec->io_switch[io_idx] = val;
1943
1944 if (val)
1945 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001946 else {
1947 unsigned int pinctl = AC_PINCTL_IN_EN;
1948 if (io_idx) /* set VREF for mic */
1949 pinctl |= stac92xx_get_vref(codec, nid);
1950 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1951 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001952
1953 /* check the auto-mute again: we need to mute/unmute the speaker
1954 * appropriately according to the pin direction
1955 */
1956 if (spec->hp_detect)
1957 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1958
Matt Porter403d1942005-11-29 15:00:51 +01001959 return 1;
1960}
1961
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001962#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1963
1964static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1965 struct snd_ctl_elem_value *ucontrol)
1966{
1967 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1968 struct sigmatel_spec *spec = codec->spec;
1969
1970 ucontrol->value.integer.value[0] = spec->clfe_swap;
1971 return 0;
1972}
1973
1974static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1975 struct snd_ctl_elem_value *ucontrol)
1976{
1977 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1978 struct sigmatel_spec *spec = codec->spec;
1979 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001980 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001981
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001982 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001983 return 0;
1984
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001985 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001986
1987 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1988 spec->clfe_swap ? 0x4 : 0x0);
1989
1990 return 1;
1991}
1992
Matt Porter403d1942005-11-29 15:00:51 +01001993#define STAC_CODEC_IO_SWITCH(xname, xpval) \
1994 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1995 .name = xname, \
1996 .index = 0, \
1997 .info = stac92xx_io_switch_info, \
1998 .get = stac92xx_io_switch_get, \
1999 .put = stac92xx_io_switch_put, \
2000 .private_value = xpval, \
2001 }
2002
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002003#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2004 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2005 .name = xname, \
2006 .index = 0, \
2007 .info = stac92xx_clfe_switch_info, \
2008 .get = stac92xx_clfe_switch_get, \
2009 .put = stac92xx_clfe_switch_put, \
2010 .private_value = xpval, \
2011 }
Matt Porter403d1942005-11-29 15:00:51 +01002012
Mattc7d4b2f2005-06-27 14:59:41 +02002013enum {
2014 STAC_CTL_WIDGET_VOL,
2015 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002016 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002017 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002018 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002019};
2020
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002021static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002022 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2023 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002024 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002025 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002026 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002027};
2028
2029/* add dynamic controls */
2030static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2031{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002032 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002033
2034 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2035 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2036
2037 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2038 if (! knew)
2039 return -ENOMEM;
2040 if (spec->kctl_alloc) {
2041 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2042 kfree(spec->kctl_alloc);
2043 }
2044 spec->kctl_alloc = knew;
2045 spec->num_kctl_alloc = num;
2046 }
2047
2048 knew = &spec->kctl_alloc[spec->num_kctl_used];
2049 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002050 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002051 if (! knew->name)
2052 return -ENOMEM;
2053 knew->private_value = val;
2054 spec->num_kctl_used++;
2055 return 0;
2056}
2057
Matt Porter403d1942005-11-29 15:00:51 +01002058/* flag inputs as additional dynamic lineouts */
2059static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2060{
2061 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002062 unsigned int wcaps, wtype;
2063 int i, num_dacs = 0;
2064
2065 /* use the wcaps cache to count all DACs available for line-outs */
2066 for (i = 0; i < codec->num_nodes; i++) {
2067 wcaps = codec->wcaps[i];
2068 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002069
Steve Longerbeam7b043892007-05-03 20:50:03 +02002070 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2071 num_dacs++;
2072 }
Matt Porter403d1942005-11-29 15:00:51 +01002073
Steve Longerbeam7b043892007-05-03 20:50:03 +02002074 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2075
Matt Porter403d1942005-11-29 15:00:51 +01002076 switch (cfg->line_outs) {
2077 case 3:
2078 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002079 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002080 cfg->line_out_pins[cfg->line_outs] =
2081 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002082 spec->line_switch = 1;
2083 cfg->line_outs++;
2084 }
2085 break;
2086 case 2:
2087 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002088 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002089 cfg->line_out_pins[cfg->line_outs] =
2090 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002091 spec->line_switch = 1;
2092 cfg->line_outs++;
2093 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002094 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002095 cfg->line_out_pins[cfg->line_outs] =
2096 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002097 spec->mic_switch = 1;
2098 cfg->line_outs++;
2099 }
2100 break;
2101 case 1:
2102 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002103 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002104 cfg->line_out_pins[cfg->line_outs] =
2105 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002106 spec->line_switch = 1;
2107 cfg->line_outs++;
2108 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002109 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002110 cfg->line_out_pins[cfg->line_outs] =
2111 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002112 spec->mic_switch = 1;
2113 cfg->line_outs++;
2114 }
2115 break;
2116 }
2117
2118 return 0;
2119}
2120
Steve Longerbeam7b043892007-05-03 20:50:03 +02002121
2122static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2123{
2124 int i;
2125
2126 for (i = 0; i < spec->multiout.num_dacs; i++) {
2127 if (spec->multiout.dac_nids[i] == nid)
2128 return 1;
2129 }
2130
2131 return 0;
2132}
2133
Matt Porter3cc08dc2006-01-23 15:27:49 +01002134/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002135 * Fill in the dac_nids table from the parsed pin configuration
2136 * This function only works when every pin in line_out_pins[]
2137 * contains atleast one DAC in its connection list. Some 92xx
2138 * codecs are not connected directly to a DAC, such as the 9200
2139 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002140 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002141static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002142 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002143{
2144 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002145 int i, j, conn_len = 0;
2146 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2147 unsigned int wcaps, wtype;
2148
Mattc7d4b2f2005-06-27 14:59:41 +02002149 for (i = 0; i < cfg->line_outs; i++) {
2150 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002151 conn_len = snd_hda_get_connections(codec, nid, conn,
2152 HDA_MAX_CONNECTIONS);
2153 for (j = 0; j < conn_len; j++) {
2154 wcaps = snd_hda_param_read(codec, conn[j],
2155 AC_PAR_AUDIO_WIDGET_CAP);
2156 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002157 if (wtype != AC_WID_AUD_OUT ||
2158 (wcaps & AC_WCAP_DIGITAL))
2159 continue;
2160 /* conn[j] is a DAC routed to this line-out */
2161 if (!is_in_dac_nids(spec, conn[j]))
2162 break;
2163 }
2164
2165 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002166 if (spec->multiout.num_dacs > 0) {
2167 /* we have already working output pins,
2168 * so let's drop the broken ones again
2169 */
2170 cfg->line_outs = spec->multiout.num_dacs;
2171 break;
2172 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002173 /* error out, no available DAC found */
2174 snd_printk(KERN_ERR
2175 "%s: No available DAC for pin 0x%x\n",
2176 __func__, nid);
2177 return -ENODEV;
2178 }
2179
2180 spec->multiout.dac_nids[i] = conn[j];
2181 spec->multiout.num_dacs++;
2182 if (conn_len > 1) {
2183 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002184 snd_hda_codec_write_cache(codec, nid, 0,
2185 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002186
2187 }
Mattc7d4b2f2005-06-27 14:59:41 +02002188 }
2189
Steve Longerbeam7b043892007-05-03 20:50:03 +02002190 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2191 spec->multiout.num_dacs,
2192 spec->multiout.dac_nids[0],
2193 spec->multiout.dac_nids[1],
2194 spec->multiout.dac_nids[2],
2195 spec->multiout.dac_nids[3],
2196 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002197 return 0;
2198}
2199
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002200/* create volume control/switch for the given prefx type */
2201static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2202{
2203 char name[32];
2204 int err;
2205
2206 sprintf(name, "%s Playback Volume", pfx);
2207 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2208 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2209 if (err < 0)
2210 return err;
2211 sprintf(name, "%s Playback Switch", pfx);
2212 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2213 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2214 if (err < 0)
2215 return err;
2216 return 0;
2217}
2218
Mattc7d4b2f2005-06-27 14:59:41 +02002219/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002220static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002221 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002222{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002223 static const char *chname[4] = {
2224 "Front", "Surround", NULL /*CLFE*/, "Side"
2225 };
Mattc7d4b2f2005-06-27 14:59:41 +02002226 hda_nid_t nid;
2227 int i, err;
2228
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002229 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002230 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002231
2232
Mattc7d4b2f2005-06-27 14:59:41 +02002233 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002234 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002235 continue;
2236
2237 nid = spec->multiout.dac_nids[i];
2238
2239 if (i == 2) {
2240 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002241 err = create_controls(spec, "Center", nid, 1);
2242 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002243 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002244 err = create_controls(spec, "LFE", nid, 2);
2245 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002246 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002247
2248 wid_caps = get_wcaps(codec, nid);
2249
2250 if (wid_caps & AC_WCAP_LR_SWAP) {
2251 err = stac92xx_add_control(spec,
2252 STAC_CTL_WIDGET_CLFE_SWITCH,
2253 "Swap Center/LFE Playback Switch", nid);
2254
2255 if (err < 0)
2256 return err;
2257 }
2258
Mattc7d4b2f2005-06-27 14:59:41 +02002259 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002260 err = create_controls(spec, chname[i], nid, 3);
2261 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002262 return err;
2263 }
2264 }
2265
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002266 if (spec->line_switch) {
2267 nid = cfg->input_pins[AUTO_PIN_LINE];
2268 pincap = snd_hda_param_read(codec, nid,
2269 AC_PAR_PIN_CAP);
2270 if (pincap & AC_PINCAP_OUT) {
2271 err = stac92xx_add_control(spec,
2272 STAC_CTL_WIDGET_IO_SWITCH,
2273 "Line In as Output Switch", nid << 8);
2274 if (err < 0)
2275 return err;
2276 }
2277 }
Matt Porter403d1942005-11-29 15:00:51 +01002278
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002279 if (spec->mic_switch) {
2280 nid = cfg->input_pins[AUTO_PIN_MIC];
2281 pincap = snd_hda_param_read(codec, nid,
2282 AC_PAR_PIN_CAP);
2283 if (pincap & AC_PINCAP_OUT) {
2284 err = stac92xx_add_control(spec,
2285 STAC_CTL_WIDGET_IO_SWITCH,
2286 "Mic as Output Switch", (nid << 8) | 1);
2287 if (err < 0)
2288 return err;
2289 }
2290 }
Matt Porter403d1942005-11-29 15:00:51 +01002291
Mattc7d4b2f2005-06-27 14:59:41 +02002292 return 0;
2293}
2294
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002295static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2296{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002297 if (is_in_dac_nids(spec, nid))
2298 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002299 if (spec->multiout.hp_nid == nid)
2300 return 1;
2301 return 0;
2302}
2303
2304static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2305{
2306 if (!spec->multiout.hp_nid)
2307 spec->multiout.hp_nid = nid;
2308 else if (spec->multiout.num_dacs > 4) {
2309 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2310 return 1;
2311 } else {
2312 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2313 spec->multiout.num_dacs++;
2314 }
2315 return 0;
2316}
2317
2318/* add playback controls for Speaker and HP outputs */
2319static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2320 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002321{
2322 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002323 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002324 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002325
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002326 old_num_dacs = spec->multiout.num_dacs;
2327 for (i = 0; i < cfg->hp_outs; i++) {
2328 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2329 if (wid_caps & AC_WCAP_UNSOL_CAP)
2330 spec->hp_detect = 1;
2331 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2332 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2333 if (check_in_dac_nids(spec, nid))
2334 nid = 0;
2335 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002336 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002337 add_spec_dacs(spec, nid);
2338 }
2339 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002340 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002341 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2342 if (check_in_dac_nids(spec, nid))
2343 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002344 if (! nid)
2345 continue;
2346 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002347 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002348 for (i = 0; i < cfg->line_outs; i++) {
2349 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2350 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2351 if (check_in_dac_nids(spec, nid))
2352 nid = 0;
2353 if (! nid)
2354 continue;
2355 add_spec_dacs(spec, nid);
2356 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002357 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2358 static const char *pfxs[] = {
2359 "Speaker", "External Speaker", "Speaker2",
2360 };
2361 err = create_controls(spec, pfxs[i - old_num_dacs],
2362 spec->multiout.dac_nids[i], 3);
2363 if (err < 0)
2364 return err;
2365 }
2366 if (spec->multiout.hp_nid) {
2367 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002368 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002369 pfx = "Master";
2370 else
2371 pfx = "Headphone";
2372 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2373 if (err < 0)
2374 return err;
2375 }
Mattc7d4b2f2005-06-27 14:59:41 +02002376
2377 return 0;
2378}
2379
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002380/* labels for mono mux outputs */
2381static const char *stac92xx_mono_labels[3] = {
2382 "DAC0", "DAC1", "Mixer"
2383};
2384
2385/* create mono mux for mono out on capable codecs */
2386static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2387{
2388 struct sigmatel_spec *spec = codec->spec;
2389 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2390 int i, num_cons;
2391 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2392
2393 num_cons = snd_hda_get_connections(codec,
2394 spec->mono_nid,
2395 con_lst,
2396 HDA_MAX_NUM_INPUTS);
2397 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2398 return -EINVAL;
2399
2400 for (i = 0; i < num_cons; i++) {
2401 mono_mux->items[mono_mux->num_items].label =
2402 stac92xx_mono_labels[i];
2403 mono_mux->items[mono_mux->num_items].index = i;
2404 mono_mux->num_items++;
2405 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002406
2407 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2408 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002409}
2410
Matt Porter8b657272006-10-26 17:12:59 +02002411/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002412static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002413 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2414 "Digital Mic 3", "Digital Mic 4"
2415};
2416
2417/* create playback/capture controls for input pins on dmic capable codecs */
2418static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2419 const struct auto_pin_cfg *cfg)
2420{
2421 struct sigmatel_spec *spec = codec->spec;
2422 struct hda_input_mux *dimux = &spec->private_dimux;
2423 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002424 int err, i, j;
2425 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002426
2427 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2428 dimux->items[dimux->num_items].index = 0;
2429 dimux->num_items++;
2430
2431 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002432 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002433 int index;
2434 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002435 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002436 unsigned int def_conf;
2437
2438 def_conf = snd_hda_codec_read(codec,
2439 spec->dmic_nids[i],
2440 0,
2441 AC_VERB_GET_CONFIG_DEFAULT,
2442 0);
2443 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2444 continue;
2445
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002446 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002447 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002448 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002449 con_lst,
2450 HDA_MAX_NUM_INPUTS);
2451 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002452 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002453 index = j;
2454 goto found;
2455 }
2456 continue;
2457found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002458 wcaps = get_wcaps(codec, nid);
2459
2460 if (wcaps & AC_WCAP_OUT_AMP) {
2461 sprintf(name, "%s Capture Volume",
2462 stac92xx_dmic_labels[dimux->num_items]);
2463
2464 err = stac92xx_add_control(spec,
2465 STAC_CTL_WIDGET_VOL,
2466 name,
2467 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2468 if (err < 0)
2469 return err;
2470 }
2471
Matt Porter8b657272006-10-26 17:12:59 +02002472 dimux->items[dimux->num_items].label =
2473 stac92xx_dmic_labels[dimux->num_items];
2474 dimux->items[dimux->num_items].index = index;
2475 dimux->num_items++;
2476 }
2477
2478 return 0;
2479}
2480
Mattc7d4b2f2005-06-27 14:59:41 +02002481/* create playback/capture controls for input pins */
2482static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2483{
2484 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002485 struct hda_input_mux *imux = &spec->private_imux;
2486 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2487 int i, j, k;
2488
2489 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002490 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002491
Takashi Iwai314634b2006-09-21 11:56:18 +02002492 if (!cfg->input_pins[i])
2493 continue;
2494 index = -1;
2495 for (j = 0; j < spec->num_muxes; j++) {
2496 int num_cons;
2497 num_cons = snd_hda_get_connections(codec,
2498 spec->mux_nids[j],
2499 con_lst,
2500 HDA_MAX_NUM_INPUTS);
2501 for (k = 0; k < num_cons; k++)
2502 if (con_lst[k] == cfg->input_pins[i]) {
2503 index = k;
2504 goto found;
2505 }
Mattc7d4b2f2005-06-27 14:59:41 +02002506 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002507 continue;
2508 found:
2509 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2510 imux->items[imux->num_items].index = index;
2511 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002512 }
2513
Steve Longerbeam7b043892007-05-03 20:50:03 +02002514 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002515 /*
2516 * Set the current input for the muxes.
2517 * The STAC9221 has two input muxes with identical source
2518 * NID lists. Hopefully this won't get confused.
2519 */
2520 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002521 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2522 AC_VERB_SET_CONNECT_SEL,
2523 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002524 }
2525 }
2526
Mattc7d4b2f2005-06-27 14:59:41 +02002527 return 0;
2528}
2529
Mattc7d4b2f2005-06-27 14:59:41 +02002530static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2531{
2532 struct sigmatel_spec *spec = codec->spec;
2533 int i;
2534
2535 for (i = 0; i < spec->autocfg.line_outs; i++) {
2536 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2537 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2538 }
2539}
2540
2541static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2542{
2543 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002544 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002545
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002546 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2547 hda_nid_t pin;
2548 pin = spec->autocfg.hp_pins[i];
2549 if (pin) /* connect to front */
2550 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2551 }
2552 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2553 hda_nid_t pin;
2554 pin = spec->autocfg.speaker_pins[i];
2555 if (pin) /* connect to front */
2556 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2557 }
Mattc7d4b2f2005-06-27 14:59:41 +02002558}
2559
Matt Porter3cc08dc2006-01-23 15:27:49 +01002560static 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 +02002561{
2562 struct sigmatel_spec *spec = codec->spec;
2563 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002564 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002565
Matt Porter8b657272006-10-26 17:12:59 +02002566 if ((err = snd_hda_parse_pin_def_config(codec,
2567 &spec->autocfg,
2568 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002569 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002570 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002571 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002572
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002573 /* If we have no real line-out pin and multiple hp-outs, HPs should
2574 * be set up as multi-channel outputs.
2575 */
2576 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2577 spec->autocfg.hp_outs > 1) {
2578 /* Copy hp_outs to line_outs, backup line_outs in
2579 * speaker_outs so that the following routines can handle
2580 * HP pins as primary outputs.
2581 */
2582 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2583 sizeof(spec->autocfg.line_out_pins));
2584 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2585 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2586 sizeof(spec->autocfg.hp_pins));
2587 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2588 hp_speaker_swap = 1;
2589 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002590 if (spec->autocfg.mono_out_pin) {
2591 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2592 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2593 u32 caps = query_amp_caps(codec,
2594 spec->autocfg.mono_out_pin, dir);
2595 hda_nid_t conn_list[1];
2596
2597 /* get the mixer node and then the mono mux if it exists */
2598 if (snd_hda_get_connections(codec,
2599 spec->autocfg.mono_out_pin, conn_list, 1) &&
2600 snd_hda_get_connections(codec, conn_list[0],
2601 conn_list, 1)) {
2602
2603 int wcaps = get_wcaps(codec, conn_list[0]);
2604 int wid_type = (wcaps & AC_WCAP_TYPE)
2605 >> AC_WCAP_TYPE_SHIFT;
2606 /* LR swap check, some stac925x have a mux that
2607 * changes the DACs output path instead of the
2608 * mono-mux path.
2609 */
2610 if (wid_type == AC_WID_AUD_SEL &&
2611 !(wcaps & AC_WCAP_LR_SWAP))
2612 spec->mono_nid = conn_list[0];
2613 }
2614 /* all mono outs have a least a mute/unmute switch */
2615 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2616 "Mono Playback Switch",
2617 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2618 1, 0, dir));
2619 if (err < 0)
2620 return err;
2621 /* check to see if there is volume support for the amp */
2622 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2623 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2624 "Mono Playback Volume",
2625 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2626 1, 0, dir));
2627 if (err < 0)
2628 return err;
2629 }
2630
2631 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2632 AC_PINCTL_OUT_EN);
2633 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002634
Matt Porter403d1942005-11-29 15:00:51 +01002635 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2636 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002637 if (spec->multiout.num_dacs == 0)
2638 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2639 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002640
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002641 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2642
2643 if (err < 0)
2644 return err;
2645
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002646 if (hp_speaker_swap == 1) {
2647 /* Restore the hp_outs and line_outs */
2648 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2649 sizeof(spec->autocfg.line_out_pins));
2650 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2651 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2652 sizeof(spec->autocfg.speaker_pins));
2653 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2654 memset(spec->autocfg.speaker_pins, 0,
2655 sizeof(spec->autocfg.speaker_pins));
2656 spec->autocfg.speaker_outs = 0;
2657 }
2658
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002659 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2660
2661 if (err < 0)
2662 return err;
2663
2664 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2665
2666 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002667 return err;
2668
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002669 if (spec->mono_nid > 0) {
2670 err = stac92xx_auto_create_mono_output_ctls(codec);
2671 if (err < 0)
2672 return err;
2673 }
2674
Matt Porter8b657272006-10-26 17:12:59 +02002675 if (spec->num_dmics > 0)
2676 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2677 &spec->autocfg)) < 0)
2678 return err;
2679
Mattc7d4b2f2005-06-27 14:59:41 +02002680 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002681 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002682 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002683
Takashi Iwai82bc9552006-03-21 11:24:42 +01002684 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002685 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002686 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002687 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002688
2689 if (spec->kctl_alloc)
2690 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2691
2692 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002693 if (!spec->dinput_mux)
2694 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002695 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002696
2697 return 1;
2698}
2699
Takashi Iwai82bc9552006-03-21 11:24:42 +01002700/* add playback controls for HP output */
2701static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2702 struct auto_pin_cfg *cfg)
2703{
2704 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002705 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002706 unsigned int wid_caps;
2707
2708 if (! pin)
2709 return 0;
2710
2711 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002712 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002713 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002714
2715 return 0;
2716}
2717
Richard Fish160ea0d2006-09-06 13:58:25 +02002718/* add playback controls for LFE output */
2719static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2720 struct auto_pin_cfg *cfg)
2721{
2722 struct sigmatel_spec *spec = codec->spec;
2723 int err;
2724 hda_nid_t lfe_pin = 0x0;
2725 int i;
2726
2727 /*
2728 * search speaker outs and line outs for a mono speaker pin
2729 * with an amp. If one is found, add LFE controls
2730 * for it.
2731 */
2732 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2733 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2734 unsigned long wcaps = get_wcaps(codec, pin);
2735 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2736 if (wcaps == AC_WCAP_OUT_AMP)
2737 /* found a mono speaker with an amp, must be lfe */
2738 lfe_pin = pin;
2739 }
2740
2741 /* if speaker_outs is 0, then speakers may be in line_outs */
2742 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2743 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2744 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2745 unsigned long cfg;
2746 cfg = snd_hda_codec_read(codec, pin, 0,
2747 AC_VERB_GET_CONFIG_DEFAULT,
2748 0x00);
2749 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2750 unsigned long wcaps = get_wcaps(codec, pin);
2751 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2752 if (wcaps == AC_WCAP_OUT_AMP)
2753 /* found a mono speaker with an amp,
2754 must be lfe */
2755 lfe_pin = pin;
2756 }
2757 }
2758 }
2759
2760 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002761 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002762 if (err < 0)
2763 return err;
2764 }
2765
2766 return 0;
2767}
2768
Mattc7d4b2f2005-06-27 14:59:41 +02002769static int stac9200_parse_auto_config(struct hda_codec *codec)
2770{
2771 struct sigmatel_spec *spec = codec->spec;
2772 int err;
2773
Kailang Yangdf694da2005-12-05 19:42:22 +01002774 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002775 return err;
2776
2777 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2778 return err;
2779
Takashi Iwai82bc9552006-03-21 11:24:42 +01002780 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2781 return err;
2782
Richard Fish160ea0d2006-09-06 13:58:25 +02002783 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2784 return err;
2785
Takashi Iwai82bc9552006-03-21 11:24:42 +01002786 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002787 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002788 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002789 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002790
2791 if (spec->kctl_alloc)
2792 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2793
2794 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002795 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002796
2797 return 1;
2798}
2799
Sam Revitch62fe78e2006-05-10 15:09:17 +02002800/*
2801 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2802 * funky external mute control using GPIO pins.
2803 */
2804
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002805static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
2806 unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002807{
2808 unsigned int gpiostate, gpiomask, gpiodir;
2809
2810 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2811 AC_VERB_GET_GPIO_DATA, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002812 gpiostate = (gpiostate & ~mask) | (data & mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002813
2814 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2815 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002816 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002817
2818 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2819 AC_VERB_GET_GPIO_DIRECTION, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002820 gpiodir |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002821
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002822 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002823 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2824
2825 snd_hda_codec_write(codec, codec->afg, 0,
2826 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002827 snd_hda_codec_read(codec, codec->afg, 0,
2828 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002829
2830 msleep(1);
2831
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002832 snd_hda_codec_read(codec, codec->afg, 0,
2833 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002834}
2835
Takashi Iwai314634b2006-09-21 11:56:18 +02002836static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2837 unsigned int event)
2838{
2839 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002840 snd_hda_codec_write_cache(codec, nid, 0,
2841 AC_VERB_SET_UNSOLICITED_ENABLE,
2842 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002843}
2844
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002845static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2846{
2847 int i;
2848 for (i = 0; i < cfg->hp_outs; i++)
2849 if (cfg->hp_pins[i] == nid)
2850 return 1; /* nid is a HP-Out */
2851
2852 return 0; /* nid is not a HP-Out */
2853};
2854
Mattc7d4b2f2005-06-27 14:59:41 +02002855static int stac92xx_init(struct hda_codec *codec)
2856{
2857 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002858 struct auto_pin_cfg *cfg = &spec->autocfg;
2859 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002860
Mattc7d4b2f2005-06-27 14:59:41 +02002861 snd_hda_sequence_write(codec, spec->init);
2862
Takashi Iwai82bc9552006-03-21 11:24:42 +01002863 /* set up pins */
2864 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002865 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002866 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002867 enable_pin_detect(codec, cfg->hp_pins[i],
2868 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002869 /* force to enable the first line-out; the others are set up
2870 * in unsol_event
2871 */
2872 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2873 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002874 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002875 /* fake event to set up pins */
2876 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2877 } else {
2878 stac92xx_auto_init_multi_out(codec);
2879 stac92xx_auto_init_hp_out(codec);
2880 }
2881 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002882 hda_nid_t nid = cfg->input_pins[i];
2883 if (nid) {
2884 unsigned int pinctl = AC_PINCTL_IN_EN;
2885 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2886 pinctl |= stac92xx_get_vref(codec, nid);
2887 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2888 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002889 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002890 for (i = 0; i < spec->num_dmics; i++)
2891 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2892 AC_PINCTL_IN_EN);
2893 for (i = 0; i < spec->num_pwrs; i++) {
2894 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2895 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2896 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2897 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2898 /* outputs are only ports capable of power management
2899 * any attempts on powering down a input port cause the
2900 * referenced VREF to act quirky.
2901 */
2902 if (pinctl & AC_PINCTL_IN_EN)
2903 continue;
2904 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2905 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2906 }
Matt Porter8b657272006-10-26 17:12:59 +02002907
Takashi Iwai82bc9552006-03-21 11:24:42 +01002908 if (cfg->dig_out_pin)
2909 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2910 AC_PINCTL_OUT_EN);
2911 if (cfg->dig_in_pin)
2912 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2913 AC_PINCTL_IN_EN);
2914
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002915 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002916
Mattc7d4b2f2005-06-27 14:59:41 +02002917 return 0;
2918}
2919
Matt2f2f4252005-04-13 14:45:30 +02002920static void stac92xx_free(struct hda_codec *codec)
2921{
Mattc7d4b2f2005-06-27 14:59:41 +02002922 struct sigmatel_spec *spec = codec->spec;
2923 int i;
2924
2925 if (! spec)
2926 return;
2927
2928 if (spec->kctl_alloc) {
2929 for (i = 0; i < spec->num_kctl_used; i++)
2930 kfree(spec->kctl_alloc[i].name);
2931 kfree(spec->kctl_alloc);
2932 }
2933
Richard Fish11b44bb2006-08-23 18:31:34 +02002934 if (spec->bios_pin_configs)
2935 kfree(spec->bios_pin_configs);
2936
Mattc7d4b2f2005-06-27 14:59:41 +02002937 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002938}
2939
Matt4e550962005-07-04 17:51:39 +02002940static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2941 unsigned int flag)
2942{
2943 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2944 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002945
Takashi Iwaif9acba42007-05-29 18:01:06 +02002946 if (pin_ctl & AC_PINCTL_IN_EN) {
2947 /*
2948 * we need to check the current set-up direction of
2949 * shared input pins since they can be switched via
2950 * "xxx as Output" mixer switch
2951 */
2952 struct sigmatel_spec *spec = codec->spec;
2953 struct auto_pin_cfg *cfg = &spec->autocfg;
2954 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2955 spec->line_switch) ||
2956 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2957 spec->mic_switch))
2958 return;
2959 }
2960
Steve Longerbeam7b043892007-05-03 20:50:03 +02002961 /* if setting pin direction bits, clear the current
2962 direction bits first */
2963 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2964 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2965
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002966 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002967 AC_VERB_SET_PIN_WIDGET_CONTROL,
2968 pin_ctl | flag);
2969}
2970
2971static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2972 unsigned int flag)
2973{
2974 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2975 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002976 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002977 AC_VERB_SET_PIN_WIDGET_CONTROL,
2978 pin_ctl & ~flag);
2979}
2980
Jiang Zhe40c1d302007-11-12 13:05:16 +01002981static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02002982{
2983 if (!nid)
2984 return 0;
2985 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01002986 & (1 << 31)) {
2987 unsigned int pinctl;
2988 pinctl = snd_hda_codec_read(codec, nid, 0,
2989 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2990 if (pinctl & AC_PINCTL_IN_EN)
2991 return 0; /* mic- or line-input */
2992 else
2993 return 1; /* HP-output */
2994 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002995 return 0;
2996}
2997
2998static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02002999{
3000 struct sigmatel_spec *spec = codec->spec;
3001 struct auto_pin_cfg *cfg = &spec->autocfg;
3002 int i, presence;
3003
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003004 presence = 0;
3005 for (i = 0; i < cfg->hp_outs; i++) {
Jiang Zhe40c1d302007-11-12 13:05:16 +01003006 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwai314634b2006-09-21 11:56:18 +02003007 if (presence)
3008 break;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003009 }
Matt4e550962005-07-04 17:51:39 +02003010
3011 if (presence) {
3012 /* disable lineouts, enable hp */
3013 for (i = 0; i < cfg->line_outs; i++)
3014 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3015 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003016 for (i = 0; i < cfg->speaker_outs; i++)
3017 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3018 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003019 } else {
3020 /* enable lineouts, disable hp */
3021 for (i = 0; i < cfg->line_outs; i++)
3022 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3023 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003024 for (i = 0; i < cfg->speaker_outs; i++)
3025 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3026 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003027 }
3028}
3029
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003030static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3031{
3032 struct sigmatel_spec *spec = codec->spec;
3033 hda_nid_t nid = spec->pwr_nids[idx];
3034 int presence, val;
3035 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3036 & 0x000000ff;
3037 presence = get_hp_pin_presence(codec, nid);
3038 idx = 1 << idx;
3039
3040 if (presence)
3041 val &= ~idx;
3042 else
3043 val |= idx;
3044
3045 /* power down unused output ports */
3046 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3047};
3048
Takashi Iwai314634b2006-09-21 11:56:18 +02003049static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3050{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003051 struct sigmatel_spec *spec = codec->spec;
3052 int idx = res >> 26 & 0x0f;
3053
3054 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003055 case STAC_HP_EVENT:
3056 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003057 /* fallthru */
3058 case STAC_PWR_EVENT:
3059 if (spec->num_pwrs > 0)
3060 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003061 }
3062}
3063
Takashi Iwaicb53c622007-08-10 17:21:45 +02003064#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003065static int stac92xx_resume(struct hda_codec *codec)
3066{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003067 struct sigmatel_spec *spec = codec->spec;
3068
Richard Fish11b44bb2006-08-23 18:31:34 +02003069 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003070 snd_hda_sequence_write(codec, spec->init);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003071 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003072 snd_hda_codec_resume_amp(codec);
3073 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003074 /* invoke unsolicited event to reset the HP state */
3075 if (spec->hp_detect)
3076 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003077 return 0;
3078}
3079#endif
3080
Matt2f2f4252005-04-13 14:45:30 +02003081static struct hda_codec_ops stac92xx_patch_ops = {
3082 .build_controls = stac92xx_build_controls,
3083 .build_pcms = stac92xx_build_pcms,
3084 .init = stac92xx_init,
3085 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003086 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003087#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003088 .resume = stac92xx_resume,
3089#endif
Matt2f2f4252005-04-13 14:45:30 +02003090};
3091
3092static int patch_stac9200(struct hda_codec *codec)
3093{
3094 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003095 int err;
Matt2f2f4252005-04-13 14:45:30 +02003096
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003097 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003098 if (spec == NULL)
3099 return -ENOMEM;
3100
3101 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003102 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003103 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003104 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3105 stac9200_models,
3106 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003107 if (spec->board_config < 0) {
3108 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3109 err = stac92xx_save_bios_config_regs(codec);
3110 if (err < 0) {
3111 stac92xx_free(codec);
3112 return err;
3113 }
3114 spec->pin_configs = spec->bios_pin_configs;
3115 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003116 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3117 stac92xx_set_config_regs(codec);
3118 }
Matt2f2f4252005-04-13 14:45:30 +02003119
3120 spec->multiout.max_channels = 2;
3121 spec->multiout.num_dacs = 1;
3122 spec->multiout.dac_nids = stac9200_dac_nids;
3123 spec->adc_nids = stac9200_adc_nids;
3124 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003125 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003126 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003127 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003128 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003129
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003130 if (spec->board_config == STAC_9200_GATEWAY)
3131 spec->init = stac9200_eapd_init;
3132 else
3133 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003134 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003135
3136 err = stac9200_parse_auto_config(codec);
3137 if (err < 0) {
3138 stac92xx_free(codec);
3139 return err;
3140 }
Matt2f2f4252005-04-13 14:45:30 +02003141
3142 codec->patch_ops = stac92xx_patch_ops;
3143
3144 return 0;
3145}
3146
Tobin Davis8e21c342007-01-08 11:04:17 +01003147static int patch_stac925x(struct hda_codec *codec)
3148{
3149 struct sigmatel_spec *spec;
3150 int err;
3151
3152 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3153 if (spec == NULL)
3154 return -ENOMEM;
3155
3156 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003157 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003158 spec->pin_nids = stac925x_pin_nids;
3159 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3160 stac925x_models,
3161 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003162 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003163 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003164 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3165 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003166 err = stac92xx_save_bios_config_regs(codec);
3167 if (err < 0) {
3168 stac92xx_free(codec);
3169 return err;
3170 }
3171 spec->pin_configs = spec->bios_pin_configs;
3172 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3173 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3174 stac92xx_set_config_regs(codec);
3175 }
3176
3177 spec->multiout.max_channels = 2;
3178 spec->multiout.num_dacs = 1;
3179 spec->multiout.dac_nids = stac925x_dac_nids;
3180 spec->adc_nids = stac925x_adc_nids;
3181 spec->mux_nids = stac925x_mux_nids;
3182 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003183 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003184 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003185 switch (codec->vendor_id) {
3186 case 0x83847632: /* STAC9202 */
3187 case 0x83847633: /* STAC9202D */
3188 case 0x83847636: /* STAC9251 */
3189 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003190 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003191 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003192 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3193 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003194 break;
3195 default:
3196 spec->num_dmics = 0;
3197 break;
3198 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003199
3200 spec->init = stac925x_core_init;
3201 spec->mixer = stac925x_mixer;
3202
3203 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003204 if (!err) {
3205 if (spec->board_config < 0) {
3206 printk(KERN_WARNING "hda_codec: No auto-config is "
3207 "available, default to model=ref\n");
3208 spec->board_config = STAC_925x_REF;
3209 goto again;
3210 }
3211 err = -EINVAL;
3212 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003213 if (err < 0) {
3214 stac92xx_free(codec);
3215 return err;
3216 }
3217
3218 codec->patch_ops = stac92xx_patch_ops;
3219
3220 return 0;
3221}
3222
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003223static struct hda_input_mux stac92hd73xx_dmux = {
3224 .num_items = 4,
3225 .items = {
3226 { "Analog Inputs", 0x0b },
3227 { "CD", 0x08 },
3228 { "Digital Mic 1", 0x09 },
3229 { "Digital Mic 2", 0x0a },
3230 }
3231};
3232
3233static int patch_stac92hd73xx(struct hda_codec *codec)
3234{
3235 struct sigmatel_spec *spec;
3236 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3237 int err = 0;
3238
3239 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3240 if (spec == NULL)
3241 return -ENOMEM;
3242
3243 codec->spec = spec;
3244 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3245 spec->pin_nids = stac92hd73xx_pin_nids;
3246 spec->board_config = snd_hda_check_board_config(codec,
3247 STAC_92HD73XX_MODELS,
3248 stac92hd73xx_models,
3249 stac92hd73xx_cfg_tbl);
3250again:
3251 if (spec->board_config < 0) {
3252 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3253 " STAC92HD73XX, using BIOS defaults\n");
3254 err = stac92xx_save_bios_config_regs(codec);
3255 if (err < 0) {
3256 stac92xx_free(codec);
3257 return err;
3258 }
3259 spec->pin_configs = spec->bios_pin_configs;
3260 } else {
3261 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3262 stac92xx_set_config_regs(codec);
3263 }
3264
3265 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3266 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3267
3268 if (spec->multiout.num_dacs < 0) {
3269 printk(KERN_WARNING "hda_codec: Could not determine "
3270 "number of channels defaulting to DAC count\n");
3271 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3272 }
3273
3274 switch (spec->multiout.num_dacs) {
3275 case 0x3: /* 6 Channel */
3276 spec->mixer = stac92hd73xx_6ch_mixer;
3277 spec->init = stac92hd73xx_6ch_core_init;
3278 break;
3279 case 0x4: /* 8 Channel */
3280 spec->multiout.hp_nid = 0x18;
3281 spec->mixer = stac92hd73xx_8ch_mixer;
3282 spec->init = stac92hd73xx_8ch_core_init;
3283 break;
3284 case 0x5: /* 10 Channel */
3285 spec->multiout.hp_nid = 0x19;
3286 spec->mixer = stac92hd73xx_10ch_mixer;
3287 spec->init = stac92hd73xx_10ch_core_init;
3288 };
3289
3290 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3291 spec->aloopback_mask = 0x01;
3292 spec->aloopback_shift = 8;
3293
3294 spec->mux_nids = stac92hd73xx_mux_nids;
3295 spec->adc_nids = stac92hd73xx_adc_nids;
3296 spec->dmic_nids = stac92hd73xx_dmic_nids;
3297 spec->dmux_nids = stac92hd73xx_dmux_nids;
3298
3299 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3300 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3301 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003302 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003303 spec->dinput_mux = &stac92hd73xx_dmux;
3304 /* GPIO0 High = Enable EAPD */
3305 spec->gpio_mask = spec->gpio_data = 0x000001;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003306
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003307 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3308 spec->pwr_nids = stac92hd73xx_pwr_nids;
3309
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003310 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3311
3312 if (!err) {
3313 if (spec->board_config < 0) {
3314 printk(KERN_WARNING "hda_codec: No auto-config is "
3315 "available, default to model=ref\n");
3316 spec->board_config = STAC_92HD73XX_REF;
3317 goto again;
3318 }
3319 err = -EINVAL;
3320 }
3321
3322 if (err < 0) {
3323 stac92xx_free(codec);
3324 return err;
3325 }
3326
3327 codec->patch_ops = stac92xx_patch_ops;
3328
3329 return 0;
3330}
3331
Matthew Ranostaye035b842007-11-06 11:53:55 +01003332static int patch_stac92hd71bxx(struct hda_codec *codec)
3333{
3334 struct sigmatel_spec *spec;
3335 int err = 0;
3336
3337 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3338 if (spec == NULL)
3339 return -ENOMEM;
3340
3341 codec->spec = spec;
3342 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3343 spec->pin_nids = stac92hd71bxx_pin_nids;
3344 spec->board_config = snd_hda_check_board_config(codec,
3345 STAC_92HD71BXX_MODELS,
3346 stac92hd71bxx_models,
3347 stac92hd71bxx_cfg_tbl);
3348again:
3349 if (spec->board_config < 0) {
3350 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3351 " STAC92HD71BXX, using BIOS defaults\n");
3352 err = stac92xx_save_bios_config_regs(codec);
3353 if (err < 0) {
3354 stac92xx_free(codec);
3355 return err;
3356 }
3357 spec->pin_configs = spec->bios_pin_configs;
3358 } else {
3359 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3360 stac92xx_set_config_regs(codec);
3361 }
3362
Matthew Ranostay541eee82007-12-14 12:08:04 +01003363 switch (codec->vendor_id) {
3364 case 0x111d76b6: /* 4 Port without Analog Mixer */
3365 case 0x111d76b7:
3366 case 0x111d76b4: /* 6 Port without Analog Mixer */
3367 case 0x111d76b5:
3368 spec->mixer = stac92hd71bxx_mixer;
3369 spec->init = stac92hd71bxx_core_init;
3370 break;
3371 default:
3372 spec->mixer = stac92hd71bxx_analog_mixer;
3373 spec->init = stac92hd71bxx_analog_core_init;
3374 }
3375
3376 spec->aloopback_mask = 0x20;
3377 spec->aloopback_shift = 0;
3378
Matthew Ranostaye035b842007-11-06 11:53:55 +01003379 spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
Matthew Ranostaye035b842007-11-06 11:53:55 +01003380
Matthew Ranostaye035b842007-11-06 11:53:55 +01003381 spec->mux_nids = stac92hd71bxx_mux_nids;
3382 spec->adc_nids = stac92hd71bxx_adc_nids;
3383 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003384 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003385
3386 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3387 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3388 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003389 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003390
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003391 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3392 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3393
Matthew Ranostaye035b842007-11-06 11:53:55 +01003394 spec->multiout.num_dacs = 2;
3395 spec->multiout.hp_nid = 0x11;
3396 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3397
3398 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3399 if (!err) {
3400 if (spec->board_config < 0) {
3401 printk(KERN_WARNING "hda_codec: No auto-config is "
3402 "available, default to model=ref\n");
3403 spec->board_config = STAC_92HD71BXX_REF;
3404 goto again;
3405 }
3406 err = -EINVAL;
3407 }
3408
3409 if (err < 0) {
3410 stac92xx_free(codec);
3411 return err;
3412 }
3413
3414 codec->patch_ops = stac92xx_patch_ops;
3415
3416 return 0;
3417};
3418
Matt2f2f4252005-04-13 14:45:30 +02003419static int patch_stac922x(struct hda_codec *codec)
3420{
3421 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003422 int err;
Matt2f2f4252005-04-13 14:45:30 +02003423
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003424 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003425 if (spec == NULL)
3426 return -ENOMEM;
3427
3428 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003429 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003430 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003431 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3432 stac922x_models,
3433 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003434 if (spec->board_config == STAC_INTEL_MAC_V3) {
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003435 spec->gpio_mask = spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003436 /* Intel Macs have all same PCI SSID, so we need to check
3437 * codec SSID to distinguish the exact models
3438 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003439 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003440 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003441
3442 case 0x106b0800:
3443 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003444 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003445 case 0x106b0600:
3446 case 0x106b0700:
3447 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003448 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003449 case 0x106b0e00:
3450 case 0x106b0f00:
3451 case 0x106b1600:
3452 case 0x106b1700:
3453 case 0x106b0200:
3454 case 0x106b1e00:
3455 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003456 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003457 case 0x106b1a00:
3458 case 0x00000100:
3459 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003460 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003461 case 0x106b0a00:
3462 case 0x106b2200:
3463 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003464 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003465 }
3466 }
3467
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003468 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003469 if (spec->board_config < 0) {
3470 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3471 "using BIOS defaults\n");
3472 err = stac92xx_save_bios_config_regs(codec);
3473 if (err < 0) {
3474 stac92xx_free(codec);
3475 return err;
3476 }
3477 spec->pin_configs = spec->bios_pin_configs;
3478 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003479 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3480 stac92xx_set_config_regs(codec);
3481 }
Matt2f2f4252005-04-13 14:45:30 +02003482
Matt2f2f4252005-04-13 14:45:30 +02003483 spec->adc_nids = stac922x_adc_nids;
3484 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003485 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003486 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003487 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003488 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003489
3490 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003491 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003492
3493 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003494
Matt Porter3cc08dc2006-01-23 15:27:49 +01003495 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003496 if (!err) {
3497 if (spec->board_config < 0) {
3498 printk(KERN_WARNING "hda_codec: No auto-config is "
3499 "available, default to model=ref\n");
3500 spec->board_config = STAC_D945_REF;
3501 goto again;
3502 }
3503 err = -EINVAL;
3504 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003505 if (err < 0) {
3506 stac92xx_free(codec);
3507 return err;
3508 }
3509
3510 codec->patch_ops = stac92xx_patch_ops;
3511
Takashi Iwai807a46362007-05-29 19:01:37 +02003512 /* Fix Mux capture level; max to 2 */
3513 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3514 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3515 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3516 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3517 (0 << AC_AMPCAP_MUTE_SHIFT));
3518
Matt Porter3cc08dc2006-01-23 15:27:49 +01003519 return 0;
3520}
3521
3522static int patch_stac927x(struct hda_codec *codec)
3523{
3524 struct sigmatel_spec *spec;
3525 int err;
3526
3527 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3528 if (spec == NULL)
3529 return -ENOMEM;
3530
3531 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003532 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003533 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003534 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3535 stac927x_models,
3536 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003537 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003538 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3539 if (spec->board_config < 0)
3540 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3541 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003542 err = stac92xx_save_bios_config_regs(codec);
3543 if (err < 0) {
3544 stac92xx_free(codec);
3545 return err;
3546 }
3547 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003548 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003549 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3550 stac92xx_set_config_regs(codec);
3551 }
3552
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003553 spec->adc_nids = stac927x_adc_nids;
3554 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3555 spec->mux_nids = stac927x_mux_nids;
3556 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
3557 spec->multiout.dac_nids = spec->dac_nids;
3558
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003559 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003560 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003561 case STAC_D965_5ST:
3562 /* GPIO0 High = Enable EAPD */
3563 spec->gpio_mask = spec->gpio_data = 0x00000001;
3564 spec->num_dmics = 0;
3565
Tobin Davis93ed1502006-09-01 21:03:12 +02003566 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003567 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003568 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003569 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003570 /* correct the front output jack as a hp out */
3571 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003572 /* correct the front input jack as a mic */
3573 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3574 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003575 case STAC_DELL_3ST:
3576 /* GPIO2 High = Enable EAPD */
3577 spec->gpio_mask = spec->gpio_data = 0x00000004;
3578 spec->dmic_nids = stac927x_dmic_nids;
3579 spec->num_dmics = STAC927X_NUM_DMICS;
3580
Tobin Davis93ed1502006-09-01 21:03:12 +02003581 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003582 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003583 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003584 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003585 break;
3586 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003587 /* GPIO0 High = Enable EAPD */
3588 spec->gpio_mask = spec->gpio_data = 0x00000001;
3589 spec->num_dmics = 0;
3590
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003591 spec->init = stac927x_core_init;
3592 spec->mixer = stac927x_mixer;
3593 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003594
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003595 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003596 spec->aloopback_mask = 0x40;
3597 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003598
Matt Porter3cc08dc2006-01-23 15:27:49 +01003599 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003600 if (!err) {
3601 if (spec->board_config < 0) {
3602 printk(KERN_WARNING "hda_codec: No auto-config is "
3603 "available, default to model=ref\n");
3604 spec->board_config = STAC_D965_REF;
3605 goto again;
3606 }
3607 err = -EINVAL;
3608 }
Mattc7d4b2f2005-06-27 14:59:41 +02003609 if (err < 0) {
3610 stac92xx_free(codec);
3611 return err;
3612 }
Matt2f2f4252005-04-13 14:45:30 +02003613
3614 codec->patch_ops = stac92xx_patch_ops;
3615
Takashi Iwai52987652008-01-16 16:09:47 +01003616 /*
3617 * !!FIXME!!
3618 * The STAC927x seem to require fairly long delays for certain
3619 * command sequences. With too short delays (even if the answer
3620 * is set to RIRB properly), it results in the silence output
3621 * on some hardwares like Dell.
3622 *
3623 * The below flag enables the longer delay (see get_response
3624 * in hda_intel.c).
3625 */
3626 codec->bus->needs_damn_long_delay = 1;
3627
Matt2f2f4252005-04-13 14:45:30 +02003628 return 0;
3629}
3630
Matt Porterf3302a52006-07-31 12:49:34 +02003631static int patch_stac9205(struct hda_codec *codec)
3632{
3633 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003634 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003635
3636 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3637 if (spec == NULL)
3638 return -ENOMEM;
3639
3640 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003641 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003642 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003643 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3644 stac9205_models,
3645 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003646 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003647 if (spec->board_config < 0) {
3648 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3649 err = stac92xx_save_bios_config_regs(codec);
3650 if (err < 0) {
3651 stac92xx_free(codec);
3652 return err;
3653 }
3654 spec->pin_configs = spec->bios_pin_configs;
3655 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003656 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3657 stac92xx_set_config_regs(codec);
3658 }
3659
3660 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003661 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003662 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003663 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003664 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003665 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003666 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003667 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003668 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003669
3670 spec->init = stac9205_core_init;
3671 spec->mixer = stac9205_mixer;
3672
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003673 spec->aloopback_mask = 0x40;
3674 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003675 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003676
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003677 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003678 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003679 /* Enable SPDIF in/out */
3680 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3681 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003682
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003683 spec->gpio_mask = 0x0000000b;
3684 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
3685 * GPIO3 High = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003686 */
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003687 spec->gpio_data = 0x00000009;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003688 break;
3689 default:
3690 /* GPIO0 High = EAPD */
3691 spec->gpio_mask = spec->gpio_data = 0x00000001;
3692 break;
3693 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003694
Matt Porterf3302a52006-07-31 12:49:34 +02003695 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003696 if (!err) {
3697 if (spec->board_config < 0) {
3698 printk(KERN_WARNING "hda_codec: No auto-config is "
3699 "available, default to model=ref\n");
3700 spec->board_config = STAC_9205_REF;
3701 goto again;
3702 }
3703 err = -EINVAL;
3704 }
Matt Porterf3302a52006-07-31 12:49:34 +02003705 if (err < 0) {
3706 stac92xx_free(codec);
3707 return err;
3708 }
3709
3710 codec->patch_ops = stac92xx_patch_ops;
3711
3712 return 0;
3713}
3714
Matt2f2f4252005-04-13 14:45:30 +02003715/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003716 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003717 */
3718
Guillaume Munch99ccc562006-08-16 19:35:12 +02003719/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003720static hda_nid_t vaio_dacs[] = { 0x2 };
3721#define VAIO_HP_DAC 0x5
3722static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3723static hda_nid_t vaio_mux_nids[] = { 0x15 };
3724
3725static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003726 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003727 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003728 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003729 { "Mic Jack", 0x1 },
3730 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003731 { "PCM", 0x3 },
3732 }
3733};
3734
3735static struct hda_verb vaio_init[] = {
3736 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003737 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003738 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3739 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3740 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3741 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003742 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003743 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3744 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3745 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3746 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3747 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3748 {}
3749};
3750
Guillaume Munch6d859062006-08-22 17:15:47 +02003751static struct hda_verb vaio_ar_init[] = {
3752 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3753 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3754 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3755 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3756/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3757 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003758 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003759 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3760 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3761/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3762 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3763 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3764 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3765 {}
3766};
3767
Takashi Iwaidb064e52006-03-16 16:04:58 +01003768/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003769static struct hda_bind_ctls vaio_bind_master_vol = {
3770 .ops = &snd_hda_bind_vol,
3771 .values = {
3772 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3773 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3774 0
3775 },
3776};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003777
3778/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003779static struct hda_bind_ctls vaio_bind_master_sw = {
3780 .ops = &snd_hda_bind_sw,
3781 .values = {
3782 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3783 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3784 0,
3785 },
3786};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003787
3788static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003789 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3790 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003791 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3792 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3793 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3794 {
3795 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3796 .name = "Capture Source",
3797 .count = 1,
3798 .info = stac92xx_mux_enum_info,
3799 .get = stac92xx_mux_enum_get,
3800 .put = stac92xx_mux_enum_put,
3801 },
3802 {}
3803};
3804
Guillaume Munch6d859062006-08-22 17:15:47 +02003805static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003806 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3807 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003808 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3809 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3810 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3811 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3812 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3813 {
3814 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3815 .name = "Capture Source",
3816 .count = 1,
3817 .info = stac92xx_mux_enum_info,
3818 .get = stac92xx_mux_enum_get,
3819 .put = stac92xx_mux_enum_put,
3820 },
3821 {}
3822};
3823
3824static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003825 .build_controls = stac92xx_build_controls,
3826 .build_pcms = stac92xx_build_pcms,
3827 .init = stac92xx_init,
3828 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003829#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003830 .resume = stac92xx_resume,
3831#endif
3832};
3833
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003834static int stac9872_vaio_init(struct hda_codec *codec)
3835{
3836 int err;
3837
3838 err = stac92xx_init(codec);
3839 if (err < 0)
3840 return err;
3841 if (codec->patch_ops.unsol_event)
3842 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3843 return 0;
3844}
3845
3846static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3847{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003848 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003849 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3850 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3851 } else {
3852 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3853 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3854 }
3855}
3856
3857static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3858{
3859 switch (res >> 26) {
3860 case STAC_HP_EVENT:
3861 stac9872_vaio_hp_detect(codec, res);
3862 break;
3863 }
3864}
3865
3866static struct hda_codec_ops stac9872_vaio_patch_ops = {
3867 .build_controls = stac92xx_build_controls,
3868 .build_pcms = stac92xx_build_pcms,
3869 .init = stac9872_vaio_init,
3870 .free = stac92xx_free,
3871 .unsol_event = stac9872_vaio_unsol_event,
3872#ifdef CONFIG_PM
3873 .resume = stac92xx_resume,
3874#endif
3875};
3876
Guillaume Munch6d859062006-08-22 17:15:47 +02003877enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3878 CXD9872RD_VAIO,
3879 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3880 STAC9872AK_VAIO,
3881 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3882 STAC9872K_VAIO,
3883 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003884 CXD9872AKD_VAIO,
3885 STAC_9872_MODELS,
3886};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003887
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003888static const char *stac9872_models[STAC_9872_MODELS] = {
3889 [CXD9872RD_VAIO] = "vaio",
3890 [CXD9872AKD_VAIO] = "vaio-ar",
3891};
3892
3893static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3894 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3895 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3896 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003897 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003898 {}
3899};
3900
Guillaume Munch6d859062006-08-22 17:15:47 +02003901static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003902{
3903 struct sigmatel_spec *spec;
3904 int board_config;
3905
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003906 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3907 stac9872_models,
3908 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003909 if (board_config < 0)
3910 /* unknown config, let generic-parser do its job... */
3911 return snd_hda_parse_generic_codec(codec);
3912
3913 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3914 if (spec == NULL)
3915 return -ENOMEM;
3916
3917 codec->spec = spec;
3918 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003919 case CXD9872RD_VAIO:
3920 case STAC9872AK_VAIO:
3921 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003922 spec->mixer = vaio_mixer;
3923 spec->init = vaio_init;
3924 spec->multiout.max_channels = 2;
3925 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3926 spec->multiout.dac_nids = vaio_dacs;
3927 spec->multiout.hp_nid = VAIO_HP_DAC;
3928 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3929 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003930 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003931 spec->input_mux = &vaio_mux;
3932 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003933 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003934 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003935
3936 case CXD9872AKD_VAIO:
3937 spec->mixer = vaio_ar_mixer;
3938 spec->init = vaio_ar_init;
3939 spec->multiout.max_channels = 2;
3940 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3941 spec->multiout.dac_nids = vaio_dacs;
3942 spec->multiout.hp_nid = VAIO_HP_DAC;
3943 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003944 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02003945 spec->adc_nids = vaio_adcs;
3946 spec->input_mux = &vaio_mux;
3947 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003948 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003949 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003950 }
3951
Takashi Iwaidb064e52006-03-16 16:04:58 +01003952 return 0;
3953}
3954
3955
3956/*
Matt2f2f4252005-04-13 14:45:30 +02003957 * patch entries
3958 */
3959struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3960 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3961 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3962 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3963 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3964 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3965 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3966 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003967 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3968 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3969 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3970 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3971 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
3972 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01003973 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
3974 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
3975 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
3976 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
3977 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
3978 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
3979 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
3980 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
3981 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
3982 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01003983 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
3984 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
3985 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
3986 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
3987 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
3988 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02003989 /* The following does not take into account .id=0x83847661 when subsys =
3990 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
3991 * currently not fully supported.
3992 */
3993 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
3994 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
3995 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02003996 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
3997 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
3998 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
3999 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4000 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4001 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4002 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4003 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004004 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4005 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004006 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004007 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4008 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4009 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4010 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4011 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4012 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4013 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4014 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4015 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004016 {} /* terminator */
4017};