blob: 4bca790e045c85c94124e19c6d28bf946ff2de76 [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include <sound/driver.h>
28#include <linux/init.h>
29#include <linux/delay.h>
30#include <linux/slab.h>
31#include <linux/pci.h>
32#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020033#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020034#include "hda_codec.h"
35#include "hda_local.h"
36
Matt4e550962005-07-04 17:51:39 +020037#define NUM_CONTROL_ALLOC 32
38#define STAC_HP_EVENT 0x37
Matt4e550962005-07-04 17:51:39 +020039
Takashi Iwaif5fcc132006-11-24 17:07:44 +010040enum {
41 STAC_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020042 STAC_9200_DELL_D21,
43 STAC_9200_DELL_D22,
44 STAC_9200_DELL_D23,
45 STAC_9200_DELL_M21,
46 STAC_9200_DELL_M22,
47 STAC_9200_DELL_M23,
48 STAC_9200_DELL_M24,
49 STAC_9200_DELL_M25,
50 STAC_9200_DELL_M26,
51 STAC_9200_DELL_M27,
Takashi 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,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100110 STAC_927X_MODELS
111};
Matt Porter403d1942005-11-29 15:00:51 +0100112
Matt2f2f4252005-04-13 14:45:30 +0200113struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100114 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200115 unsigned int num_mixers;
116
Matt Porter403d1942005-11-29 15:00:51 +0100117 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200118 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100119 unsigned int line_switch: 1;
120 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100121 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100122 unsigned int hp_detect: 1;
Sam Revitch62fe78e2006-05-10 15:09:17 +0200123 unsigned int gpio_mute: 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
Matt2f2f4252005-04-13 14:45:30 +0200129 /* playback */
130 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100131 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200132
133 /* capture */
134 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200135 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200136 hda_nid_t *mux_nids;
137 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200138 hda_nid_t *dmic_nids;
139 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100140 hda_nid_t *dmux_nids;
Mattdabbed62005-06-14 10:19:34 +0200141 hda_nid_t dig_in_nid;
Matt2f2f4252005-04-13 14:45:30 +0200142
Matt2f2f4252005-04-13 14:45:30 +0200143 /* pin widgets */
144 hda_nid_t *pin_nids;
145 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200146 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200147 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200148
149 /* codec specific stuff */
150 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100151 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200152
153 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200154 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100155 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200156 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100157 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200158
Matt Porter403d1942005-11-29 15:00:51 +0100159 /* i/o switches */
160 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200161 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200162 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200163
Mattc7d4b2f2005-06-27 14:59:41 +0200164 struct hda_pcm pcm_rec[2]; /* PCM information */
165
166 /* dynamic controls and input_mux */
167 struct auto_pin_cfg autocfg;
168 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100169 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200170 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200171 struct hda_input_mux private_imux;
Matt2f2f4252005-04-13 14:45:30 +0200172};
173
174static hda_nid_t stac9200_adc_nids[1] = {
175 0x03,
176};
177
178static hda_nid_t stac9200_mux_nids[1] = {
179 0x0c,
180};
181
182static hda_nid_t stac9200_dac_nids[1] = {
183 0x02,
184};
185
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100186static hda_nid_t stac92hd73xx_adc_nids[2] = {
187 0x1a, 0x1b
188};
189
190#define STAC92HD73XX_NUM_DMICS 2
191static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
192 0x13, 0x14, 0
193};
194
195#define STAC92HD73_DAC_COUNT 5
196static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
197 0x15, 0x16, 0x17, 0x18, 0x19,
198};
199
200static hda_nid_t stac92hd73xx_mux_nids[4] = {
201 0x28, 0x29, 0x2a, 0x2b,
202};
203
204static hda_nid_t stac92hd73xx_dmux_nids[2] = {
205 0x20, 0x21,
206};
207
Matthew Ranostaye035b842007-11-06 11:53:55 +0100208static hda_nid_t stac92hd71bxx_adc_nids[2] = {
209 0x12, 0x13,
210};
211
212static hda_nid_t stac92hd71bxx_mux_nids[2] = {
213 0x1a, 0x1b
214};
215
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100216static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
217 0x1c,
218};
219
Matthew Ranostaye035b842007-11-06 11:53:55 +0100220static hda_nid_t stac92hd71bxx_dac_nids[2] = {
221 0x10, /*0x11, */
222};
223
224#define STAC92HD71BXX_NUM_DMICS 2
225static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
226 0x18, 0x19, 0
227};
228
Tobin Davis8e21c342007-01-08 11:04:17 +0100229static hda_nid_t stac925x_adc_nids[1] = {
230 0x03,
231};
232
233static hda_nid_t stac925x_mux_nids[1] = {
234 0x0f,
235};
236
237static hda_nid_t stac925x_dac_nids[1] = {
238 0x02,
239};
240
Takashi Iwaif6e98522007-10-16 14:27:04 +0200241#define STAC925X_NUM_DMICS 1
242static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
243 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200244};
245
Matt2f2f4252005-04-13 14:45:30 +0200246static hda_nid_t stac922x_adc_nids[2] = {
247 0x06, 0x07,
248};
249
250static hda_nid_t stac922x_mux_nids[2] = {
251 0x12, 0x13,
252};
253
Matt Porter3cc08dc2006-01-23 15:27:49 +0100254static hda_nid_t stac927x_adc_nids[3] = {
255 0x07, 0x08, 0x09
256};
257
258static hda_nid_t stac927x_mux_nids[3] = {
259 0x15, 0x16, 0x17
260};
261
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100262static hda_nid_t stac927x_dmux_nids[1] = {
263 0x1b,
264};
265
Matthew Ranostay7f168592007-10-18 17:38:17 +0200266#define STAC927X_NUM_DMICS 2
267static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
268 0x13, 0x14, 0
269};
270
Matt Porterf3302a52006-07-31 12:49:34 +0200271static hda_nid_t stac9205_adc_nids[2] = {
272 0x12, 0x13
273};
274
275static hda_nid_t stac9205_mux_nids[2] = {
276 0x19, 0x1a
277};
278
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100279static hda_nid_t stac9205_dmux_nids[1] = {
280 0x1d,
281};
282
Takashi Iwaif6e98522007-10-16 14:27:04 +0200283#define STAC9205_NUM_DMICS 2
284static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
285 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200286};
287
Mattc7d4b2f2005-06-27 14:59:41 +0200288static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200289 0x08, 0x09, 0x0d, 0x0e,
290 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200291};
292
Tobin Davis8e21c342007-01-08 11:04:17 +0100293static hda_nid_t stac925x_pin_nids[8] = {
294 0x07, 0x08, 0x0a, 0x0b,
295 0x0c, 0x0d, 0x10, 0x11,
296};
297
Matt2f2f4252005-04-13 14:45:30 +0200298static hda_nid_t stac922x_pin_nids[10] = {
299 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
300 0x0f, 0x10, 0x11, 0x15, 0x1b,
301};
302
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100303static hda_nid_t stac92hd73xx_pin_nids[12] = {
304 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
305 0x0f, 0x10, 0x11, 0x12, 0x13,
306 0x14, 0x22
307};
308
Matthew Ranostaye035b842007-11-06 11:53:55 +0100309static hda_nid_t stac92hd71bxx_pin_nids[10] = {
310 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
311 0x0f, 0x14, 0x18, 0x19, 0x1e,
312};
313
Matt Porter3cc08dc2006-01-23 15:27:49 +0100314static hda_nid_t stac927x_pin_nids[14] = {
315 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
316 0x0f, 0x10, 0x11, 0x12, 0x13,
317 0x14, 0x21, 0x22, 0x23,
318};
319
Matt Porterf3302a52006-07-31 12:49:34 +0200320static hda_nid_t stac9205_pin_nids[12] = {
321 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
322 0x0f, 0x14, 0x16, 0x17, 0x18,
323 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200324};
325
Matt Porter8b657272006-10-26 17:12:59 +0200326static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
327 struct snd_ctl_elem_info *uinfo)
328{
329 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
330 struct sigmatel_spec *spec = codec->spec;
331 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
332}
333
334static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
335 struct snd_ctl_elem_value *ucontrol)
336{
337 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
338 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100339 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200340
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100341 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200342 return 0;
343}
344
345static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
346 struct snd_ctl_elem_value *ucontrol)
347{
348 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
349 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100350 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200351
352 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100353 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200354}
355
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100356static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200357{
358 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
359 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200360 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200361}
362
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100363static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200364{
365 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
366 struct sigmatel_spec *spec = codec->spec;
367 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
368
369 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
370 return 0;
371}
372
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100373static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200374{
375 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
376 struct sigmatel_spec *spec = codec->spec;
377 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
378
Mattc7d4b2f2005-06-27 14:59:41 +0200379 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200380 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
381}
382
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200383#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
384
385static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
386 struct snd_ctl_elem_value *ucontrol)
387{
388 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100389 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200390 struct sigmatel_spec *spec = codec->spec;
391
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100392 ucontrol->value.integer.value[0] = !!(spec->aloopback &
393 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200394 return 0;
395}
396
397static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
398 struct snd_ctl_elem_value *ucontrol)
399{
400 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
401 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100402 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200403 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100404 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200405
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100406 idx_val = spec->aloopback_mask << idx;
407 if (ucontrol->value.integer.value[0])
408 val = spec->aloopback | idx_val;
409 else
410 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100411 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200412 return 0;
413
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100414 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200415
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100416 /* Only return the bits defined by the shift value of the
417 * first two bytes of the mask
418 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200419 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100420 kcontrol->private_value & 0xFFFF, 0x0);
421 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200422
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100423 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200424 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100425 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200426 } else {
427 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100428 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200429 }
430
431 snd_hda_codec_write_cache(codec, codec->afg, 0,
432 kcontrol->private_value >> 16, dac_mode);
433
434 return 1;
435}
436
Mattc7d4b2f2005-06-27 14:59:41 +0200437static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200438 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200439 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200440 {}
441};
442
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200443static struct hda_verb stac9200_eapd_init[] = {
444 /* set dac0mux for dac converter */
445 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
446 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
447 {}
448};
449
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100450static struct hda_verb stac92hd73xx_6ch_core_init[] = {
451 /* set master volume and direct control */
452 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
453 /* setup audio connections */
454 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
455 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
456 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
457 /* setup adcs to point to mixer */
458 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
459 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
460 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Front Mic */
461 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic */
462 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Line In */
463 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
464 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
465 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
466 /* setup import muxs */
467 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
468 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
469 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
470 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
471 {}
472};
473
474static struct hda_verb stac92hd73xx_8ch_core_init[] = {
475 /* set master volume and direct control */
476 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
477 /* setup audio connections */
478 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
479 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
480 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
481 /* connect hp ports to dac3 */
482 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
483 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
484 /* setup adcs to point to mixer */
485 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
486 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
487 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Front Mic */
488 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic */
489 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Line In */
490 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
491 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
492 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
493 /* setup import muxs */
494 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
495 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
496 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
497 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
498 {}
499};
500
501static struct hda_verb stac92hd73xx_10ch_core_init[] = {
502 /* set master volume and direct control */
503 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
504 /* setup audio connections */
505 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
506 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
507 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
508 /* dac3 is connected to import3 mux */
509 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
510 /* connect hp ports to dac4 */
511 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
512 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
513 /* setup adcs to point to mixer */
514 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
515 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
516 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Front Mic */
517 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Mic */
518 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Line In */
519 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
520 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
521 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
522 /* setup import muxs */
523 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
524 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
525 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
526 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
527 {}
528};
529
Matthew Ranostaye035b842007-11-06 11:53:55 +0100530static struct hda_verb stac92hd71bxx_core_init[] = {
531 /* set master volume and direct control */
532 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
533 /* connect headphone jack to dac1 */
534 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100535 /* connect ports 0d and 0f to audio mixer */
536 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
537 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
538 /* unmute dac0 input in audio mixer */
539 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100540 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
541 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
542 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
543 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
544 /* unmute mono out node */
545 { 0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
546 {}
547};
548
Tobin Davis8e21c342007-01-08 11:04:17 +0100549static struct hda_verb stac925x_core_init[] = {
550 /* set dac0mux for dac converter */
551 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
552 {}
553};
554
Mattc7d4b2f2005-06-27 14:59:41 +0200555static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200556 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200557 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200558 {}
559};
560
Tobin Davis93ed1502006-09-01 21:03:12 +0200561static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200562 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200563 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200564 /* unmute node 0x1b */
565 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
566 /* select node 0x03 as DAC */
567 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
568 {}
569};
570
Matt Porter3cc08dc2006-01-23 15:27:49 +0100571static struct hda_verb stac927x_core_init[] = {
572 /* set master volume and direct control */
573 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
574 {}
575};
576
Matt Porterf3302a52006-07-31 12:49:34 +0200577static struct hda_verb stac9205_core_init[] = {
578 /* set master volume and direct control */
579 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
580 {}
581};
582
Matthew Ranostay47744f62007-10-19 08:19:56 +0200583#define STAC_DIGITAL_INPUT_SOURCE(cnt) \
584 { \
585 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
586 .name = "Digital Input Source", \
587 .count = cnt, \
588 .info = stac92xx_dmux_enum_info, \
589 .get = stac92xx_dmux_enum_get, \
590 .put = stac92xx_dmux_enum_put,\
591 }
592
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200593#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200594 { \
595 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
596 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200597 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200598 .info = stac92xx_mux_enum_info, \
599 .get = stac92xx_mux_enum_get, \
600 .put = stac92xx_mux_enum_put, \
601 }
602
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100603#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200604 { \
605 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
606 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100607 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200608 .info = stac92xx_aloopback_info, \
609 .get = stac92xx_aloopback_get, \
610 .put = stac92xx_aloopback_put, \
611 .private_value = verb_read | (verb_write << 16), \
612 }
613
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100614static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200615 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
616 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200617 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200618 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
619 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200620 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200621 { } /* end */
622};
623
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100624static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
625 STAC_DIGITAL_INPUT_SOURCE(2),
626 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
627
628 /* hardware gain controls */
Matthew Ranostay71685b92007-12-14 12:07:31 +0100629 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x0, 0x13, 0x0, HDA_INPUT),
630 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x14, 0x0, HDA_INPUT),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100631
632 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
633 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
634
635 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
636 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
637
638 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
639 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
640
641 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
642 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
643
644 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
645 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
646
647 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
648 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
649
650 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
651 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
652 { } /* end */
653};
654
655static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
656 STAC_DIGITAL_INPUT_SOURCE(2),
657 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
658
659 /* hardware gain controls */
Matthew Ranostay71685b92007-12-14 12:07:31 +0100660 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x0, 0x13, 0x0, HDA_INPUT),
661 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x14, 0x0, HDA_INPUT),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100662
663 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
664 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
665
666 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
667 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
668
669 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
670 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
671
672 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
673 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
674
675 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
676 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
677
678 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
679 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
680
681 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
682 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
683 { } /* end */
684};
685
686static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
687 STAC_DIGITAL_INPUT_SOURCE(2),
688 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
689
690 /* hardware gain controls */
Matthew Ranostay71685b92007-12-14 12:07:31 +0100691 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x0, 0x13, 0x0, HDA_INPUT),
692 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x14, 0x0, HDA_INPUT),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100693
694 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
695 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
696
697 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
698 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
699
700 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
701 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
702
703 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
704 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
705
706 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
707 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
708
709 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
710 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
711
712 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
713 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
714 { } /* end */
715};
716
Matthew Ranostaye035b842007-11-06 11:53:55 +0100717static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
718 STAC_DIGITAL_INPUT_SOURCE(1),
719 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100720
721 /* hardware gain controls */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100722 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x0, 0x18, 0x0, HDA_OUTPUT),
723 HDA_CODEC_VOLUME_IDX("Digital Mic Volume", 0x1, 0x19, 0x0, HDA_OUTPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100724
Matthew Ranostay9b359472007-11-07 13:03:12 +0100725 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
726 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
727 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
728
729 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
730 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
731 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
732
733 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
734 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100735 { } /* end */
736};
737
Tobin Davis8e21c342007-01-08 11:04:17 +0100738static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200739 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100740 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
741 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
742 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
743 { } /* end */
744};
745
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100746static struct snd_kcontrol_new stac9205_mixer[] = {
Matthew Ranostay47744f62007-10-19 08:19:56 +0200747 STAC_DIGITAL_INPUT_SOURCE(1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200748 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100749 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200750
751 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
752 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
753 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
754
755 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
756 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
757 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
758
759 { } /* end */
760};
761
762/* This needs to be generated dynamically based on sequence */
763static struct snd_kcontrol_new stac922x_mixer[] = {
764 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200765 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
766 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
767 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
768
769 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
770 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
771 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
772 { } /* end */
773};
774
775
776static struct snd_kcontrol_new stac927x_mixer[] = {
Matthew Ranostay47744f62007-10-19 08:19:56 +0200777 STAC_DIGITAL_INPUT_SOURCE(1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200778 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100779 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200780
781 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
782 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
783 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
784
785 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
786 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
787 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
788
789 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
790 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
791 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200792 { } /* end */
793};
794
Matt2f2f4252005-04-13 14:45:30 +0200795static int stac92xx_build_controls(struct hda_codec *codec)
796{
797 struct sigmatel_spec *spec = codec->spec;
798 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200799 int i;
Matt2f2f4252005-04-13 14:45:30 +0200800
801 err = snd_hda_add_new_ctls(codec, spec->mixer);
802 if (err < 0)
803 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200804
805 for (i = 0; i < spec->num_mixers; i++) {
806 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
807 if (err < 0)
808 return err;
809 }
810
Mattdabbed62005-06-14 10:19:34 +0200811 if (spec->multiout.dig_out_nid) {
812 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
813 if (err < 0)
814 return err;
815 }
816 if (spec->dig_in_nid) {
817 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
818 if (err < 0)
819 return err;
820 }
821 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200822}
823
Matt Porter403d1942005-11-29 15:00:51 +0100824static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200825 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200826 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
827};
828
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200829/*
830 STAC 9200 pin configs for
831 102801A8
832 102801DE
833 102801E8
834*/
835static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200836 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
837 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200838};
839
840/*
841 STAC 9200 pin configs for
842 102801C0
843 102801C1
844*/
845static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200846 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
847 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200848};
849
850/*
851 STAC 9200 pin configs for
852 102801C4 (Dell Dimension E310)
853 102801C5
854 102801C7
855 102801D9
856 102801DA
857 102801E3
858*/
859static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200860 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
861 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200862};
863
864
865/*
866 STAC 9200-32 pin configs for
867 102801B5 (Dell Inspiron 630m)
868 102801D8 (Dell Inspiron 640m)
869*/
870static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200871 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
872 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200873};
874
875/*
876 STAC 9200-32 pin configs for
877 102801C2 (Dell Latitude D620)
878 102801C8
879 102801CC (Dell Latitude D820)
880 102801D4
881 102801D6
882*/
883static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200884 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
885 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200886};
887
888/*
889 STAC 9200-32 pin configs for
890 102801CE (Dell XPS M1710)
891 102801CF (Dell Precision M90)
892*/
893static unsigned int dell9200_m23_pin_configs[8] = {
894 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
895 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
896};
897
898/*
899 STAC 9200-32 pin configs for
900 102801C9
901 102801CA
902 102801CB (Dell Latitude 120L)
903 102801D3
904*/
905static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200906 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
907 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200908};
909
910/*
911 STAC 9200-32 pin configs for
912 102801BD (Dell Inspiron E1505n)
913 102801EE
914 102801EF
915*/
916static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200917 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
918 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200919};
920
921/*
922 STAC 9200-32 pin configs for
923 102801F5 (Dell Inspiron 1501)
924 102801F6
925*/
926static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200927 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
928 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200929};
930
931/*
932 STAC 9200-32
933 102801CD (Dell Inspiron E1705/9400)
934*/
935static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200936 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
937 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200938};
939
940
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100941static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
942 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200943 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
944 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
945 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
946 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
947 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
948 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
949 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
950 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
951 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
952 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +0100953};
954
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100955static const char *stac9200_models[STAC_9200_MODELS] = {
956 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200957 [STAC_9200_DELL_D21] = "dell-d21",
958 [STAC_9200_DELL_D22] = "dell-d22",
959 [STAC_9200_DELL_D23] = "dell-d23",
960 [STAC_9200_DELL_M21] = "dell-m21",
961 [STAC_9200_DELL_M22] = "dell-m22",
962 [STAC_9200_DELL_M23] = "dell-m23",
963 [STAC_9200_DELL_M24] = "dell-m24",
964 [STAC_9200_DELL_M25] = "dell-m25",
965 [STAC_9200_DELL_M26] = "dell-m26",
966 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200967 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100968};
969
970static struct snd_pci_quirk stac9200_cfg_tbl[] = {
971 /* SigmaTel reference board */
972 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
973 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +0100974 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200975 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
976 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100977 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200978 "Dell Inspiron 630m", STAC_9200_DELL_M21),
979 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
980 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
981 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
982 "unknown Dell", STAC_9200_DELL_D22),
983 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
984 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100985 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200986 "Dell Latitude D620", STAC_9200_DELL_M22),
987 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
988 "unknown Dell", STAC_9200_DELL_D23),
989 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
990 "unknown Dell", STAC_9200_DELL_D23),
991 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
992 "unknown Dell", STAC_9200_DELL_M22),
993 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
994 "unknown Dell", STAC_9200_DELL_M24),
995 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
996 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100997 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200998 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +0100999 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001000 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001001 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001002 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001003 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001004 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001005 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001006 "Dell Precision M90", STAC_9200_DELL_M23),
1007 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1008 "unknown Dell", STAC_9200_DELL_M22),
1009 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1010 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001011 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001012 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001013 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001014 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1015 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1016 "unknown Dell", STAC_9200_DELL_D23),
1017 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1018 "unknown Dell", STAC_9200_DELL_D23),
1019 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1020 "unknown Dell", STAC_9200_DELL_D21),
1021 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1022 "unknown Dell", STAC_9200_DELL_D23),
1023 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1024 "unknown Dell", STAC_9200_DELL_D21),
1025 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1026 "unknown Dell", STAC_9200_DELL_M25),
1027 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1028 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001029 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001030 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1031 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1032 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001033 /* Panasonic */
1034 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001035 /* Gateway machines needs EAPD to be set on resume */
1036 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1037 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1038 STAC_9200_GATEWAY),
1039 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1040 STAC_9200_GATEWAY),
Matt Porter403d1942005-11-29 15:00:51 +01001041 {} /* terminator */
1042};
1043
Tobin Davis8e21c342007-01-08 11:04:17 +01001044static unsigned int ref925x_pin_configs[8] = {
1045 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1046 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
1047};
1048
1049static unsigned int stac925x_MA6_pin_configs[8] = {
1050 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1051 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1052};
1053
Tobin Davis2c11f952007-05-17 09:36:34 +02001054static unsigned int stac925x_PA6_pin_configs[8] = {
1055 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1056 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1057};
1058
Tobin Davis8e21c342007-01-08 11:04:17 +01001059static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001060 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1061 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001062};
1063
1064static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1065 [STAC_REF] = ref925x_pin_configs,
1066 [STAC_M2_2] = stac925xM2_2_pin_configs,
1067 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001068 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001069};
1070
1071static const char *stac925x_models[STAC_925x_MODELS] = {
1072 [STAC_REF] = "ref",
1073 [STAC_M2_2] = "m2-2",
1074 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001075 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001076};
1077
1078static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1079 /* SigmaTel reference board */
1080 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001081 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001082 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1083 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1084 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001085 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001086 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1087 {} /* terminator */
1088};
1089
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001090static unsigned int ref92hd73xx_pin_configs[12] = {
1091 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1092 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1093 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1094};
1095
1096static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1097 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1098};
1099
1100static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1101 [STAC_92HD73XX_REF] = "ref",
1102};
1103
1104static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1105 /* SigmaTel reference board */
1106 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1107 "DFI LanParty", STAC_92HD73XX_REF),
1108 {} /* terminator */
1109};
1110
Matthew Ranostaye035b842007-11-06 11:53:55 +01001111static unsigned int ref92hd71bxx_pin_configs[10] = {
1112 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
1113 0x0181302e, 0x01114010, 0x01a19020, 0x90a000f0,
1114 0x90a000f0, 0x01452050,
1115};
1116
1117static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1118 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1119};
1120
1121static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1122 [STAC_92HD71BXX_REF] = "ref",
1123};
1124
1125static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1126 /* SigmaTel reference board */
1127 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1128 "DFI LanParty", STAC_92HD71BXX_REF),
1129 {} /* terminator */
1130};
1131
Matt Porter403d1942005-11-29 15:00:51 +01001132static unsigned int ref922x_pin_configs[10] = {
1133 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1134 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001135 0x40000100, 0x40000100,
1136};
1137
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001138/*
1139 STAC 922X pin configs for
1140 102801A7
1141 102801AB
1142 102801A9
1143 102801D1
1144 102801D2
1145*/
1146static unsigned int dell_922x_d81_pin_configs[10] = {
1147 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1148 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1149 0x01813122, 0x400001f2,
1150};
1151
1152/*
1153 STAC 922X pin configs for
1154 102801AC
1155 102801D0
1156*/
1157static unsigned int dell_922x_d82_pin_configs[10] = {
1158 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1159 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1160 0x01813122, 0x400001f1,
1161};
1162
1163/*
1164 STAC 922X pin configs for
1165 102801BF
1166*/
1167static unsigned int dell_922x_m81_pin_configs[10] = {
1168 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1169 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1170 0x40C003f1, 0x405003f0,
1171};
1172
1173/*
1174 STAC 9221 A1 pin configs for
1175 102801D7 (Dell XPS M1210)
1176*/
1177static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001178 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1179 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001180 0x508003f3, 0x405003f4,
1181};
1182
Matt Porter403d1942005-11-29 15:00:51 +01001183static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001184 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001185 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1186 0x02a19120, 0x40000100,
1187};
1188
1189static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001190 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1191 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001192 0x02a19320, 0x40000100,
1193};
1194
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001195static unsigned int intel_mac_v1_pin_configs[10] = {
1196 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1197 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001198 0x400000fc, 0x400000fb,
1199};
1200
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001201static unsigned int intel_mac_v2_pin_configs[10] = {
1202 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1203 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001204 0x400000fc, 0x400000fb,
1205};
1206
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001207static unsigned int intel_mac_v3_pin_configs[10] = {
1208 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1209 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1210 0x400000fc, 0x400000fb,
1211};
1212
1213static unsigned int intel_mac_v4_pin_configs[10] = {
1214 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1215 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1216 0x400000fc, 0x400000fb,
1217};
1218
1219static unsigned int intel_mac_v5_pin_configs[10] = {
1220 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1221 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1222 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001223};
1224
Takashi Iwai76c08822007-06-19 12:17:42 +02001225
Takashi Iwai19039bd2006-06-28 15:52:16 +02001226static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001227 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001228 [STAC_D945GTP3] = d945gtp3_pin_configs,
1229 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001230 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1231 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1232 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1233 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1234 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001235 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001236 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1237 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1238 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1239 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1240 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1241 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001242 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1243 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1244 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1245 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001246};
1247
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001248static const char *stac922x_models[STAC_922X_MODELS] = {
1249 [STAC_D945_REF] = "ref",
1250 [STAC_D945GTP5] = "5stack",
1251 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001252 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1253 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1254 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1255 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1256 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001257 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001258 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001259 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001260 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1261 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001262 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001263 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001264 [STAC_922X_DELL_D81] = "dell-d81",
1265 [STAC_922X_DELL_D82] = "dell-d82",
1266 [STAC_922X_DELL_M81] = "dell-m81",
1267 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001268};
1269
1270static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1271 /* SigmaTel reference board */
1272 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1273 "DFI LanParty", STAC_D945_REF),
1274 /* Intel 945G based systems */
1275 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1276 "Intel D945G", STAC_D945GTP3),
1277 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1278 "Intel D945G", STAC_D945GTP3),
1279 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1280 "Intel D945G", STAC_D945GTP3),
1281 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1282 "Intel D945G", STAC_D945GTP3),
1283 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1284 "Intel D945G", STAC_D945GTP3),
1285 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1286 "Intel D945G", STAC_D945GTP3),
1287 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1288 "Intel D945G", STAC_D945GTP3),
1289 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1290 "Intel D945G", STAC_D945GTP3),
1291 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1292 "Intel D945G", STAC_D945GTP3),
1293 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1294 "Intel D945G", STAC_D945GTP3),
1295 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1296 "Intel D945G", STAC_D945GTP3),
1297 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1298 "Intel D945G", STAC_D945GTP3),
1299 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1300 "Intel D945G", STAC_D945GTP3),
1301 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1302 "Intel D945G", STAC_D945GTP3),
1303 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1304 "Intel D945G", STAC_D945GTP3),
1305 /* Intel D945G 5-stack systems */
1306 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1307 "Intel D945G", STAC_D945GTP5),
1308 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1309 "Intel D945G", STAC_D945GTP5),
1310 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1311 "Intel D945G", STAC_D945GTP5),
1312 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1313 "Intel D945G", STAC_D945GTP5),
1314 /* Intel 945P based systems */
1315 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1316 "Intel D945P", STAC_D945GTP3),
1317 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1318 "Intel D945P", STAC_D945GTP3),
1319 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1320 "Intel D945P", STAC_D945GTP3),
1321 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1322 "Intel D945P", STAC_D945GTP3),
1323 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1324 "Intel D945P", STAC_D945GTP3),
1325 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1326 "Intel D945P", STAC_D945GTP5),
1327 /* other systems */
1328 /* Apple Mac Mini (early 2006) */
1329 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001330 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001331 /* Dell systems */
1332 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1333 "unknown Dell", STAC_922X_DELL_D81),
1334 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1335 "unknown Dell", STAC_922X_DELL_D81),
1336 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1337 "unknown Dell", STAC_922X_DELL_D81),
1338 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1339 "unknown Dell", STAC_922X_DELL_D82),
1340 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1341 "unknown Dell", STAC_922X_DELL_M81),
1342 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1343 "unknown Dell", STAC_922X_DELL_D82),
1344 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1345 "unknown Dell", STAC_922X_DELL_D81),
1346 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1347 "unknown Dell", STAC_922X_DELL_D81),
1348 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1349 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001350 {} /* terminator */
1351};
1352
Matt Porter3cc08dc2006-01-23 15:27:49 +01001353static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001354 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1355 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1356 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1357 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001358};
1359
Tobin Davis93ed1502006-09-01 21:03:12 +02001360static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001361 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1362 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1363 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1364 0x40000100, 0x40000100
1365};
1366
Tobin Davis93ed1502006-09-01 21:03:12 +02001367static unsigned int d965_5st_pin_configs[14] = {
1368 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1369 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1370 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1371 0x40000100, 0x40000100
1372};
1373
Tobin Davis4ff076e2007-08-07 11:48:12 +02001374static unsigned int dell_3st_pin_configs[14] = {
1375 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1376 0x01111212, 0x01116211, 0x01813050, 0x01112214,
1377 0x403003fa, 0x40000100, 0x40000100, 0x404003fb,
1378 0x40c003fc, 0x40000100
1379};
1380
Tobin Davis93ed1502006-09-01 21:03:12 +02001381static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001382 [STAC_D965_REF] = ref927x_pin_configs,
Tobin Davis93ed1502006-09-01 21:03:12 +02001383 [STAC_D965_3ST] = d965_3st_pin_configs,
1384 [STAC_D965_5ST] = d965_5st_pin_configs,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001385 [STAC_DELL_3ST] = dell_3st_pin_configs,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001386};
1387
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001388static const char *stac927x_models[STAC_927X_MODELS] = {
1389 [STAC_D965_REF] = "ref",
1390 [STAC_D965_3ST] = "3stack",
1391 [STAC_D965_5ST] = "5stack",
Tobin Davis4ff076e2007-08-07 11:48:12 +02001392 [STAC_DELL_3ST] = "dell-3stack",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001393};
1394
1395static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1396 /* SigmaTel reference board */
1397 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1398 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001399 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001400 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1401 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001402 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001403 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1404 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1405 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1406 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1407 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1408 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1409 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1410 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1411 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1412 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1413 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1414 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1415 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1416 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1417 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1418 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tim Gardner5e915bb2007-10-10 10:42:00 +02001419 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001420 /* Dell 3 stack systems */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001421 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001422 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1423 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001424 /* 965 based 5 stack systems */
Tim Gardner5e915bb2007-10-10 10:42:00 +02001425 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_D965_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001426 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1427 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1428 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1429 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1430 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1431 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1432 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1433 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1434 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001435 {} /* terminator */
1436};
1437
Matt Porterf3302a52006-07-31 12:49:34 +02001438static unsigned int ref9205_pin_configs[12] = {
1439 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matt Porter8b657272006-10-26 17:12:59 +02001440 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
1441 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001442};
1443
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001444/*
1445 STAC 9205 pin configs for
1446 102801F1
1447 102801F2
1448 102801FC
1449 102801FD
1450 10280204
1451 1028021F
1452*/
1453static unsigned int dell_9205_m42_pin_configs[12] = {
1454 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1455 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1456 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1457};
1458
1459/*
1460 STAC 9205 pin configs for
1461 102801F9
1462 102801FA
1463 102801FE
1464 102801FF (Dell Precision M4300)
1465 10280206
1466 10280200
1467 10280201
1468*/
1469static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001470 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1471 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1472 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1473};
1474
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001475static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001476 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1477 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1478 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1479};
1480
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001481static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001482 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001483 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1484 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1485 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001486};
1487
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001488static const char *stac9205_models[STAC_9205_MODELS] = {
1489 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001490 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001491 [STAC_9205_DELL_M43] = "dell-m43",
1492 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001493};
1494
1495static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1496 /* SigmaTel reference board */
1497 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1498 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001499 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1500 "unknown Dell", STAC_9205_DELL_M42),
1501 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1502 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001503 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001504 "Dell Precision", STAC_9205_DELL_M43),
1505 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1506 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001507 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1508 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001509 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1510 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001511 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1512 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001513 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1514 "unknown Dell", STAC_9205_DELL_M42),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1516 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001517 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1518 "Dell Precision", STAC_9205_DELL_M43),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001520 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001521 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1522 "Dell Precision", STAC_9205_DELL_M43),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1524 "Dell Inspiron", STAC_9205_DELL_M44),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1526 "Dell Inspiron", STAC_9205_DELL_M44),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1528 "Dell Inspiron", STAC_9205_DELL_M44),
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1530 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001531 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1532 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001533 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1534 "Dell Inspiron", STAC_9205_DELL_M44),
Matt Porterf3302a52006-07-31 12:49:34 +02001535 {} /* terminator */
1536};
1537
Richard Fish11b44bb2006-08-23 18:31:34 +02001538static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1539{
1540 int i;
1541 struct sigmatel_spec *spec = codec->spec;
1542
1543 if (! spec->bios_pin_configs) {
1544 spec->bios_pin_configs = kcalloc(spec->num_pins,
1545 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1546 if (! spec->bios_pin_configs)
1547 return -ENOMEM;
1548 }
1549
1550 for (i = 0; i < spec->num_pins; i++) {
1551 hda_nid_t nid = spec->pin_nids[i];
1552 unsigned int pin_cfg;
1553
1554 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1555 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1556 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1557 nid, pin_cfg);
1558 spec->bios_pin_configs[i] = pin_cfg;
1559 }
1560
1561 return 0;
1562}
1563
Matthew Ranostay87d48362007-07-17 11:52:24 +02001564static void stac92xx_set_config_reg(struct hda_codec *codec,
1565 hda_nid_t pin_nid, unsigned int pin_config)
1566{
1567 int i;
1568 snd_hda_codec_write(codec, pin_nid, 0,
1569 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1570 pin_config & 0x000000ff);
1571 snd_hda_codec_write(codec, pin_nid, 0,
1572 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1573 (pin_config & 0x0000ff00) >> 8);
1574 snd_hda_codec_write(codec, pin_nid, 0,
1575 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1576 (pin_config & 0x00ff0000) >> 16);
1577 snd_hda_codec_write(codec, pin_nid, 0,
1578 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1579 pin_config >> 24);
1580 i = snd_hda_codec_read(codec, pin_nid, 0,
1581 AC_VERB_GET_CONFIG_DEFAULT,
1582 0x00);
1583 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1584 pin_nid, i);
1585}
1586
Matt2f2f4252005-04-13 14:45:30 +02001587static void stac92xx_set_config_regs(struct hda_codec *codec)
1588{
1589 int i;
1590 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001591
Matthew Ranostay87d48362007-07-17 11:52:24 +02001592 if (!spec->pin_configs)
1593 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001594
Matthew Ranostay87d48362007-07-17 11:52:24 +02001595 for (i = 0; i < spec->num_pins; i++)
1596 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1597 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001598}
Matt2f2f4252005-04-13 14:45:30 +02001599
Takashi Iwai82599802007-07-31 15:56:24 +02001600static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
Matthew Ranostay92a22be2007-06-19 16:48:28 +02001601{
Takashi Iwai82599802007-07-31 15:56:24 +02001602 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay87d48362007-07-17 11:52:24 +02001603 /* Configure GPIOx as output */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001604 snd_hda_codec_write_cache(codec, codec->afg, 0,
1605 AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001606 /* Configure GPIOx as CMOS */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001607 snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001608 /* Assert GPIOx */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001609 snd_hda_codec_write_cache(codec, codec->afg, 0,
1610 AC_VERB_SET_GPIO_DATA, spec->gpio_data);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001611 /* Enable GPIOx */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001612 snd_hda_codec_write_cache(codec, codec->afg, 0,
1613 AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
Matthew Ranostay92a22be2007-06-19 16:48:28 +02001614}
1615
Matt2f2f4252005-04-13 14:45:30 +02001616/*
1617 * Analog playback callbacks
1618 */
1619static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1620 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001621 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001622{
1623 struct sigmatel_spec *spec = codec->spec;
1624 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1625}
1626
1627static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1628 struct hda_codec *codec,
1629 unsigned int stream_tag,
1630 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001631 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001632{
1633 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001634 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001635}
1636
1637static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1638 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001639 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001640{
1641 struct sigmatel_spec *spec = codec->spec;
1642 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1643}
1644
1645/*
Mattdabbed62005-06-14 10:19:34 +02001646 * Digital playback callbacks
1647 */
1648static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1649 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001650 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001651{
1652 struct sigmatel_spec *spec = codec->spec;
1653 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1654}
1655
1656static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1657 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001658 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001659{
1660 struct sigmatel_spec *spec = codec->spec;
1661 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1662}
1663
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001664static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1665 struct hda_codec *codec,
1666 unsigned int stream_tag,
1667 unsigned int format,
1668 struct snd_pcm_substream *substream)
1669{
1670 struct sigmatel_spec *spec = codec->spec;
1671 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1672 stream_tag, format, substream);
1673}
1674
Mattdabbed62005-06-14 10:19:34 +02001675
1676/*
Matt2f2f4252005-04-13 14:45:30 +02001677 * Analog capture callbacks
1678 */
1679static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1680 struct hda_codec *codec,
1681 unsigned int stream_tag,
1682 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001683 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001684{
1685 struct sigmatel_spec *spec = codec->spec;
1686
1687 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1688 stream_tag, 0, format);
1689 return 0;
1690}
1691
1692static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1693 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001694 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001695{
1696 struct sigmatel_spec *spec = codec->spec;
1697
1698 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1699 return 0;
1700}
1701
Mattdabbed62005-06-14 10:19:34 +02001702static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1703 .substreams = 1,
1704 .channels_min = 2,
1705 .channels_max = 2,
1706 /* NID is set in stac92xx_build_pcms */
1707 .ops = {
1708 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001709 .close = stac92xx_dig_playback_pcm_close,
1710 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001711 },
1712};
1713
1714static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1715 .substreams = 1,
1716 .channels_min = 2,
1717 .channels_max = 2,
1718 /* NID is set in stac92xx_build_pcms */
1719};
1720
Matt2f2f4252005-04-13 14:45:30 +02001721static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1722 .substreams = 1,
1723 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001724 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001725 .nid = 0x02, /* NID to query formats and rates */
1726 .ops = {
1727 .open = stac92xx_playback_pcm_open,
1728 .prepare = stac92xx_playback_pcm_prepare,
1729 .cleanup = stac92xx_playback_pcm_cleanup
1730 },
1731};
1732
Matt Porter3cc08dc2006-01-23 15:27:49 +01001733static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1734 .substreams = 1,
1735 .channels_min = 2,
1736 .channels_max = 2,
1737 .nid = 0x06, /* NID to query formats and rates */
1738 .ops = {
1739 .open = stac92xx_playback_pcm_open,
1740 .prepare = stac92xx_playback_pcm_prepare,
1741 .cleanup = stac92xx_playback_pcm_cleanup
1742 },
1743};
1744
Matt2f2f4252005-04-13 14:45:30 +02001745static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001746 .channels_min = 2,
1747 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001748 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001749 .ops = {
1750 .prepare = stac92xx_capture_pcm_prepare,
1751 .cleanup = stac92xx_capture_pcm_cleanup
1752 },
1753};
1754
1755static int stac92xx_build_pcms(struct hda_codec *codec)
1756{
1757 struct sigmatel_spec *spec = codec->spec;
1758 struct hda_pcm *info = spec->pcm_rec;
1759
1760 codec->num_pcms = 1;
1761 codec->pcm_info = info;
1762
Mattc7d4b2f2005-06-27 14:59:41 +02001763 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001764 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001765 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001766 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001767 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001768
1769 if (spec->alt_switch) {
1770 codec->num_pcms++;
1771 info++;
1772 info->name = "STAC92xx Analog Alt";
1773 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1774 }
Matt2f2f4252005-04-13 14:45:30 +02001775
Mattdabbed62005-06-14 10:19:34 +02001776 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1777 codec->num_pcms++;
1778 info++;
1779 info->name = "STAC92xx Digital";
1780 if (spec->multiout.dig_out_nid) {
1781 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1782 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1783 }
1784 if (spec->dig_in_nid) {
1785 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1786 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1787 }
1788 }
1789
Matt2f2f4252005-04-13 14:45:30 +02001790 return 0;
1791}
1792
Takashi Iwaic960a032006-03-23 17:06:28 +01001793static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1794{
1795 unsigned int pincap = snd_hda_param_read(codec, nid,
1796 AC_PAR_PIN_CAP);
1797 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1798 if (pincap & AC_PINCAP_VREF_100)
1799 return AC_PINCTL_VREF_100;
1800 if (pincap & AC_PINCAP_VREF_80)
1801 return AC_PINCTL_VREF_80;
1802 if (pincap & AC_PINCAP_VREF_50)
1803 return AC_PINCTL_VREF_50;
1804 if (pincap & AC_PINCAP_VREF_GRD)
1805 return AC_PINCTL_VREF_GRD;
1806 return 0;
1807}
1808
Matt Porter403d1942005-11-29 15:00:51 +01001809static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1810
1811{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001812 snd_hda_codec_write_cache(codec, nid, 0,
1813 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001814}
1815
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001816#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001817
1818static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1819{
1820 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1821 struct sigmatel_spec *spec = codec->spec;
1822 int io_idx = kcontrol-> private_value & 0xff;
1823
1824 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1825 return 0;
1826}
1827
1828static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1829{
1830 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1831 struct sigmatel_spec *spec = codec->spec;
1832 hda_nid_t nid = kcontrol->private_value >> 8;
1833 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001834 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001835
1836 spec->io_switch[io_idx] = val;
1837
1838 if (val)
1839 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001840 else {
1841 unsigned int pinctl = AC_PINCTL_IN_EN;
1842 if (io_idx) /* set VREF for mic */
1843 pinctl |= stac92xx_get_vref(codec, nid);
1844 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1845 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001846
1847 /* check the auto-mute again: we need to mute/unmute the speaker
1848 * appropriately according to the pin direction
1849 */
1850 if (spec->hp_detect)
1851 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1852
Matt Porter403d1942005-11-29 15:00:51 +01001853 return 1;
1854}
1855
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001856#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1857
1858static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1859 struct snd_ctl_elem_value *ucontrol)
1860{
1861 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1862 struct sigmatel_spec *spec = codec->spec;
1863
1864 ucontrol->value.integer.value[0] = spec->clfe_swap;
1865 return 0;
1866}
1867
1868static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1869 struct snd_ctl_elem_value *ucontrol)
1870{
1871 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1872 struct sigmatel_spec *spec = codec->spec;
1873 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001874 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001875
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001876 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001877 return 0;
1878
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001879 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001880
1881 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1882 spec->clfe_swap ? 0x4 : 0x0);
1883
1884 return 1;
1885}
1886
Matt Porter403d1942005-11-29 15:00:51 +01001887#define STAC_CODEC_IO_SWITCH(xname, xpval) \
1888 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1889 .name = xname, \
1890 .index = 0, \
1891 .info = stac92xx_io_switch_info, \
1892 .get = stac92xx_io_switch_get, \
1893 .put = stac92xx_io_switch_put, \
1894 .private_value = xpval, \
1895 }
1896
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001897#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
1898 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1899 .name = xname, \
1900 .index = 0, \
1901 .info = stac92xx_clfe_switch_info, \
1902 .get = stac92xx_clfe_switch_get, \
1903 .put = stac92xx_clfe_switch_put, \
1904 .private_value = xpval, \
1905 }
Matt Porter403d1942005-11-29 15:00:51 +01001906
Mattc7d4b2f2005-06-27 14:59:41 +02001907enum {
1908 STAC_CTL_WIDGET_VOL,
1909 STAC_CTL_WIDGET_MUTE,
Matt Porter403d1942005-11-29 15:00:51 +01001910 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001911 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02001912};
1913
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001914static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02001915 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
1916 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matt Porter403d1942005-11-29 15:00:51 +01001917 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001918 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02001919};
1920
1921/* add dynamic controls */
1922static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
1923{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001924 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02001925
1926 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
1927 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
1928
1929 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
1930 if (! knew)
1931 return -ENOMEM;
1932 if (spec->kctl_alloc) {
1933 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
1934 kfree(spec->kctl_alloc);
1935 }
1936 spec->kctl_alloc = knew;
1937 spec->num_kctl_alloc = num;
1938 }
1939
1940 knew = &spec->kctl_alloc[spec->num_kctl_used];
1941 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02001942 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02001943 if (! knew->name)
1944 return -ENOMEM;
1945 knew->private_value = val;
1946 spec->num_kctl_used++;
1947 return 0;
1948}
1949
Matt Porter403d1942005-11-29 15:00:51 +01001950/* flag inputs as additional dynamic lineouts */
1951static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
1952{
1953 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02001954 unsigned int wcaps, wtype;
1955 int i, num_dacs = 0;
1956
1957 /* use the wcaps cache to count all DACs available for line-outs */
1958 for (i = 0; i < codec->num_nodes; i++) {
1959 wcaps = codec->wcaps[i];
1960 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
1961 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
1962 num_dacs++;
1963 }
Matt Porter403d1942005-11-29 15:00:51 +01001964
Steve Longerbeam7b043892007-05-03 20:50:03 +02001965 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
1966
Matt Porter403d1942005-11-29 15:00:51 +01001967 switch (cfg->line_outs) {
1968 case 3:
1969 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02001970 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001971 cfg->line_out_pins[cfg->line_outs] =
1972 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01001973 spec->line_switch = 1;
1974 cfg->line_outs++;
1975 }
1976 break;
1977 case 2:
1978 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02001979 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001980 cfg->line_out_pins[cfg->line_outs] =
1981 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01001982 spec->line_switch = 1;
1983 cfg->line_outs++;
1984 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02001985 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001986 cfg->line_out_pins[cfg->line_outs] =
1987 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01001988 spec->mic_switch = 1;
1989 cfg->line_outs++;
1990 }
1991 break;
1992 case 1:
1993 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02001994 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02001995 cfg->line_out_pins[cfg->line_outs] =
1996 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01001997 spec->line_switch = 1;
1998 cfg->line_outs++;
1999 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002000 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002001 cfg->line_out_pins[cfg->line_outs] =
2002 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002003 spec->mic_switch = 1;
2004 cfg->line_outs++;
2005 }
2006 break;
2007 }
2008
2009 return 0;
2010}
2011
Steve Longerbeam7b043892007-05-03 20:50:03 +02002012
2013static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2014{
2015 int i;
2016
2017 for (i = 0; i < spec->multiout.num_dacs; i++) {
2018 if (spec->multiout.dac_nids[i] == nid)
2019 return 1;
2020 }
2021
2022 return 0;
2023}
2024
Matt Porter3cc08dc2006-01-23 15:27:49 +01002025/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002026 * Fill in the dac_nids table from the parsed pin configuration
2027 * This function only works when every pin in line_out_pins[]
2028 * contains atleast one DAC in its connection list. Some 92xx
2029 * codecs are not connected directly to a DAC, such as the 9200
2030 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002031 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002032static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002033 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002034{
2035 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002036 int i, j, conn_len = 0;
2037 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2038 unsigned int wcaps, wtype;
2039
Mattc7d4b2f2005-06-27 14:59:41 +02002040 for (i = 0; i < cfg->line_outs; i++) {
2041 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002042 conn_len = snd_hda_get_connections(codec, nid, conn,
2043 HDA_MAX_CONNECTIONS);
2044 for (j = 0; j < conn_len; j++) {
2045 wcaps = snd_hda_param_read(codec, conn[j],
2046 AC_PAR_AUDIO_WIDGET_CAP);
2047 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
2048
2049 if (wtype != AC_WID_AUD_OUT ||
2050 (wcaps & AC_WCAP_DIGITAL))
2051 continue;
2052 /* conn[j] is a DAC routed to this line-out */
2053 if (!is_in_dac_nids(spec, conn[j]))
2054 break;
2055 }
2056
2057 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002058 if (spec->multiout.num_dacs > 0) {
2059 /* we have already working output pins,
2060 * so let's drop the broken ones again
2061 */
2062 cfg->line_outs = spec->multiout.num_dacs;
2063 break;
2064 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002065 /* error out, no available DAC found */
2066 snd_printk(KERN_ERR
2067 "%s: No available DAC for pin 0x%x\n",
2068 __func__, nid);
2069 return -ENODEV;
2070 }
2071
2072 spec->multiout.dac_nids[i] = conn[j];
2073 spec->multiout.num_dacs++;
2074 if (conn_len > 1) {
2075 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002076 snd_hda_codec_write_cache(codec, nid, 0,
2077 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002078
2079 }
Mattc7d4b2f2005-06-27 14:59:41 +02002080 }
2081
Steve Longerbeam7b043892007-05-03 20:50:03 +02002082 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2083 spec->multiout.num_dacs,
2084 spec->multiout.dac_nids[0],
2085 spec->multiout.dac_nids[1],
2086 spec->multiout.dac_nids[2],
2087 spec->multiout.dac_nids[3],
2088 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002089 return 0;
2090}
2091
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002092/* create volume control/switch for the given prefx type */
2093static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2094{
2095 char name[32];
2096 int err;
2097
2098 sprintf(name, "%s Playback Volume", pfx);
2099 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2100 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2101 if (err < 0)
2102 return err;
2103 sprintf(name, "%s Playback Switch", pfx);
2104 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2105 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2106 if (err < 0)
2107 return err;
2108 return 0;
2109}
2110
Mattc7d4b2f2005-06-27 14:59:41 +02002111/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002112static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002113 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002114{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002115 static const char *chname[4] = {
2116 "Front", "Surround", NULL /*CLFE*/, "Side"
2117 };
Mattc7d4b2f2005-06-27 14:59:41 +02002118 hda_nid_t nid;
2119 int i, err;
2120
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002121 struct sigmatel_spec *spec = codec->spec;
2122 unsigned int wid_caps;
2123
2124
Mattc7d4b2f2005-06-27 14:59:41 +02002125 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002126 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002127 continue;
2128
2129 nid = spec->multiout.dac_nids[i];
2130
2131 if (i == 2) {
2132 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002133 err = create_controls(spec, "Center", nid, 1);
2134 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002135 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002136 err = create_controls(spec, "LFE", nid, 2);
2137 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002138 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002139
2140 wid_caps = get_wcaps(codec, nid);
2141
2142 if (wid_caps & AC_WCAP_LR_SWAP) {
2143 err = stac92xx_add_control(spec,
2144 STAC_CTL_WIDGET_CLFE_SWITCH,
2145 "Swap Center/LFE Playback Switch", nid);
2146
2147 if (err < 0)
2148 return err;
2149 }
2150
Mattc7d4b2f2005-06-27 14:59:41 +02002151 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002152 err = create_controls(spec, chname[i], nid, 3);
2153 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002154 return err;
2155 }
2156 }
2157
Matt Porter403d1942005-11-29 15:00:51 +01002158 if (spec->line_switch)
2159 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
2160 return err;
2161
2162 if (spec->mic_switch)
2163 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
2164 return err;
2165
Mattc7d4b2f2005-06-27 14:59:41 +02002166 return 0;
2167}
2168
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002169static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2170{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002171 if (is_in_dac_nids(spec, nid))
2172 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002173 if (spec->multiout.hp_nid == nid)
2174 return 1;
2175 return 0;
2176}
2177
2178static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2179{
2180 if (!spec->multiout.hp_nid)
2181 spec->multiout.hp_nid = nid;
2182 else if (spec->multiout.num_dacs > 4) {
2183 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2184 return 1;
2185 } else {
2186 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2187 spec->multiout.num_dacs++;
2188 }
2189 return 0;
2190}
2191
2192/* add playback controls for Speaker and HP outputs */
2193static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2194 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002195{
2196 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002197 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002198 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002199
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002200 old_num_dacs = spec->multiout.num_dacs;
2201 for (i = 0; i < cfg->hp_outs; i++) {
2202 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2203 if (wid_caps & AC_WCAP_UNSOL_CAP)
2204 spec->hp_detect = 1;
2205 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2206 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2207 if (check_in_dac_nids(spec, nid))
2208 nid = 0;
2209 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002210 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002211 add_spec_dacs(spec, nid);
2212 }
2213 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002214 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002215 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2216 if (check_in_dac_nids(spec, nid))
2217 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002218 if (! nid)
2219 continue;
2220 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002221 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002222 for (i = 0; i < cfg->line_outs; i++) {
2223 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2224 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2225 if (check_in_dac_nids(spec, nid))
2226 nid = 0;
2227 if (! nid)
2228 continue;
2229 add_spec_dacs(spec, nid);
2230 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002231 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2232 static const char *pfxs[] = {
2233 "Speaker", "External Speaker", "Speaker2",
2234 };
2235 err = create_controls(spec, pfxs[i - old_num_dacs],
2236 spec->multiout.dac_nids[i], 3);
2237 if (err < 0)
2238 return err;
2239 }
2240 if (spec->multiout.hp_nid) {
2241 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002242 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002243 pfx = "Master";
2244 else
2245 pfx = "Headphone";
2246 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2247 if (err < 0)
2248 return err;
2249 }
Mattc7d4b2f2005-06-27 14:59:41 +02002250
2251 return 0;
2252}
2253
Matt Porter8b657272006-10-26 17:12:59 +02002254/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002255static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002256 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2257 "Digital Mic 3", "Digital Mic 4"
2258};
2259
2260/* create playback/capture controls for input pins on dmic capable codecs */
2261static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2262 const struct auto_pin_cfg *cfg)
2263{
2264 struct sigmatel_spec *spec = codec->spec;
2265 struct hda_input_mux *dimux = &spec->private_dimux;
2266 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2267 int i, j;
2268
2269 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2270 dimux->items[dimux->num_items].index = 0;
2271 dimux->num_items++;
2272
2273 for (i = 0; i < spec->num_dmics; i++) {
2274 int index;
2275 int num_cons;
2276 unsigned int def_conf;
2277
2278 def_conf = snd_hda_codec_read(codec,
2279 spec->dmic_nids[i],
2280 0,
2281 AC_VERB_GET_CONFIG_DEFAULT,
2282 0);
2283 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2284 continue;
2285
2286 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002287 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002288 con_lst,
2289 HDA_MAX_NUM_INPUTS);
2290 for (j = 0; j < num_cons; j++)
2291 if (con_lst[j] == spec->dmic_nids[i]) {
2292 index = j;
2293 goto found;
2294 }
2295 continue;
2296found:
2297 dimux->items[dimux->num_items].label =
2298 stac92xx_dmic_labels[dimux->num_items];
2299 dimux->items[dimux->num_items].index = index;
2300 dimux->num_items++;
2301 }
2302
2303 return 0;
2304}
2305
Mattc7d4b2f2005-06-27 14:59:41 +02002306/* create playback/capture controls for input pins */
2307static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2308{
2309 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002310 struct hda_input_mux *imux = &spec->private_imux;
2311 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2312 int i, j, k;
2313
2314 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002315 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002316
Takashi Iwai314634b2006-09-21 11:56:18 +02002317 if (!cfg->input_pins[i])
2318 continue;
2319 index = -1;
2320 for (j = 0; j < spec->num_muxes; j++) {
2321 int num_cons;
2322 num_cons = snd_hda_get_connections(codec,
2323 spec->mux_nids[j],
2324 con_lst,
2325 HDA_MAX_NUM_INPUTS);
2326 for (k = 0; k < num_cons; k++)
2327 if (con_lst[k] == cfg->input_pins[i]) {
2328 index = k;
2329 goto found;
2330 }
Mattc7d4b2f2005-06-27 14:59:41 +02002331 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002332 continue;
2333 found:
2334 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2335 imux->items[imux->num_items].index = index;
2336 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002337 }
2338
Steve Longerbeam7b043892007-05-03 20:50:03 +02002339 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002340 /*
2341 * Set the current input for the muxes.
2342 * The STAC9221 has two input muxes with identical source
2343 * NID lists. Hopefully this won't get confused.
2344 */
2345 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002346 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2347 AC_VERB_SET_CONNECT_SEL,
2348 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002349 }
2350 }
2351
Mattc7d4b2f2005-06-27 14:59:41 +02002352 return 0;
2353}
2354
Mattc7d4b2f2005-06-27 14:59:41 +02002355static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2356{
2357 struct sigmatel_spec *spec = codec->spec;
2358 int i;
2359
2360 for (i = 0; i < spec->autocfg.line_outs; i++) {
2361 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2362 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2363 }
2364}
2365
2366static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2367{
2368 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002369 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002370
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002371 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2372 hda_nid_t pin;
2373 pin = spec->autocfg.hp_pins[i];
2374 if (pin) /* connect to front */
2375 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2376 }
2377 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2378 hda_nid_t pin;
2379 pin = spec->autocfg.speaker_pins[i];
2380 if (pin) /* connect to front */
2381 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2382 }
Mattc7d4b2f2005-06-27 14:59:41 +02002383}
2384
Matt Porter3cc08dc2006-01-23 15:27:49 +01002385static 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 +02002386{
2387 struct sigmatel_spec *spec = codec->spec;
2388 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002389 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002390
Matt Porter8b657272006-10-26 17:12:59 +02002391 if ((err = snd_hda_parse_pin_def_config(codec,
2392 &spec->autocfg,
2393 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002394 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002395 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002396 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002397
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002398 /* If we have no real line-out pin and multiple hp-outs, HPs should
2399 * be set up as multi-channel outputs.
2400 */
2401 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2402 spec->autocfg.hp_outs > 1) {
2403 /* Copy hp_outs to line_outs, backup line_outs in
2404 * speaker_outs so that the following routines can handle
2405 * HP pins as primary outputs.
2406 */
2407 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2408 sizeof(spec->autocfg.line_out_pins));
2409 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2410 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2411 sizeof(spec->autocfg.hp_pins));
2412 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2413 hp_speaker_swap = 1;
2414 }
2415
Matt Porter403d1942005-11-29 15:00:51 +01002416 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2417 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002418 if (spec->multiout.num_dacs == 0)
2419 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2420 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002421
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002422 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2423
2424 if (err < 0)
2425 return err;
2426
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002427 if (hp_speaker_swap == 1) {
2428 /* Restore the hp_outs and line_outs */
2429 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2430 sizeof(spec->autocfg.line_out_pins));
2431 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2432 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2433 sizeof(spec->autocfg.speaker_pins));
2434 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2435 memset(spec->autocfg.speaker_pins, 0,
2436 sizeof(spec->autocfg.speaker_pins));
2437 spec->autocfg.speaker_outs = 0;
2438 }
2439
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002440 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2441
2442 if (err < 0)
2443 return err;
2444
2445 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2446
2447 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002448 return err;
2449
Matt Porter8b657272006-10-26 17:12:59 +02002450 if (spec->num_dmics > 0)
2451 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2452 &spec->autocfg)) < 0)
2453 return err;
2454
Mattc7d4b2f2005-06-27 14:59:41 +02002455 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002456 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002457 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002458
Takashi Iwai82bc9552006-03-21 11:24:42 +01002459 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002460 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002461 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002462 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002463
2464 if (spec->kctl_alloc)
2465 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2466
2467 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002468 if (!spec->dinput_mux)
2469 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002470
2471 return 1;
2472}
2473
Takashi Iwai82bc9552006-03-21 11:24:42 +01002474/* add playback controls for HP output */
2475static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2476 struct auto_pin_cfg *cfg)
2477{
2478 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002479 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002480 unsigned int wid_caps;
2481
2482 if (! pin)
2483 return 0;
2484
2485 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002486 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002487 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002488
2489 return 0;
2490}
2491
Richard Fish160ea0d2006-09-06 13:58:25 +02002492/* add playback controls for LFE output */
2493static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2494 struct auto_pin_cfg *cfg)
2495{
2496 struct sigmatel_spec *spec = codec->spec;
2497 int err;
2498 hda_nid_t lfe_pin = 0x0;
2499 int i;
2500
2501 /*
2502 * search speaker outs and line outs for a mono speaker pin
2503 * with an amp. If one is found, add LFE controls
2504 * for it.
2505 */
2506 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2507 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2508 unsigned long wcaps = get_wcaps(codec, pin);
2509 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2510 if (wcaps == AC_WCAP_OUT_AMP)
2511 /* found a mono speaker with an amp, must be lfe */
2512 lfe_pin = pin;
2513 }
2514
2515 /* if speaker_outs is 0, then speakers may be in line_outs */
2516 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2517 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2518 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2519 unsigned long cfg;
2520 cfg = snd_hda_codec_read(codec, pin, 0,
2521 AC_VERB_GET_CONFIG_DEFAULT,
2522 0x00);
2523 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2524 unsigned long wcaps = get_wcaps(codec, pin);
2525 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2526 if (wcaps == AC_WCAP_OUT_AMP)
2527 /* found a mono speaker with an amp,
2528 must be lfe */
2529 lfe_pin = pin;
2530 }
2531 }
2532 }
2533
2534 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002535 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002536 if (err < 0)
2537 return err;
2538 }
2539
2540 return 0;
2541}
2542
Mattc7d4b2f2005-06-27 14:59:41 +02002543static int stac9200_parse_auto_config(struct hda_codec *codec)
2544{
2545 struct sigmatel_spec *spec = codec->spec;
2546 int err;
2547
Kailang Yangdf694da2005-12-05 19:42:22 +01002548 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002549 return err;
2550
2551 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2552 return err;
2553
Takashi Iwai82bc9552006-03-21 11:24:42 +01002554 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2555 return err;
2556
Richard Fish160ea0d2006-09-06 13:58:25 +02002557 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2558 return err;
2559
Takashi Iwai82bc9552006-03-21 11:24:42 +01002560 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002561 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002562 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002563 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002564
2565 if (spec->kctl_alloc)
2566 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2567
2568 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002569 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002570
2571 return 1;
2572}
2573
Sam Revitch62fe78e2006-05-10 15:09:17 +02002574/*
2575 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2576 * funky external mute control using GPIO pins.
2577 */
2578
2579static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
2580{
2581 unsigned int gpiostate, gpiomask, gpiodir;
2582
2583 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2584 AC_VERB_GET_GPIO_DATA, 0);
2585
2586 if (!muted)
2587 gpiostate |= (1 << pin);
2588 else
2589 gpiostate &= ~(1 << pin);
2590
2591 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2592 AC_VERB_GET_GPIO_MASK, 0);
2593 gpiomask |= (1 << pin);
2594
2595 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2596 AC_VERB_GET_GPIO_DIRECTION, 0);
2597 gpiodir |= (1 << pin);
2598
2599 /* AppleHDA seems to do this -- WTF is this verb?? */
2600 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2601
2602 snd_hda_codec_write(codec, codec->afg, 0,
2603 AC_VERB_SET_GPIO_MASK, gpiomask);
2604 snd_hda_codec_write(codec, codec->afg, 0,
2605 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
2606
2607 msleep(1);
2608
2609 snd_hda_codec_write(codec, codec->afg, 0,
2610 AC_VERB_SET_GPIO_DATA, gpiostate);
2611}
2612
Takashi Iwai314634b2006-09-21 11:56:18 +02002613static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2614 unsigned int event)
2615{
2616 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002617 snd_hda_codec_write_cache(codec, nid, 0,
2618 AC_VERB_SET_UNSOLICITED_ENABLE,
2619 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002620}
2621
Mattc7d4b2f2005-06-27 14:59:41 +02002622static int stac92xx_init(struct hda_codec *codec)
2623{
2624 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002625 struct auto_pin_cfg *cfg = &spec->autocfg;
2626 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002627
Mattc7d4b2f2005-06-27 14:59:41 +02002628 snd_hda_sequence_write(codec, spec->init);
2629
Takashi Iwai82bc9552006-03-21 11:24:42 +01002630 /* set up pins */
2631 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002632 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002633 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002634 enable_pin_detect(codec, cfg->hp_pins[i],
2635 STAC_HP_EVENT);
Takashi Iwai0a07aca2007-03-13 10:40:23 +01002636 /* force to enable the first line-out; the others are set up
2637 * in unsol_event
2638 */
2639 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2640 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002641 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002642 /* fake event to set up pins */
2643 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2644 } else {
2645 stac92xx_auto_init_multi_out(codec);
2646 stac92xx_auto_init_hp_out(codec);
2647 }
2648 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002649 hda_nid_t nid = cfg->input_pins[i];
2650 if (nid) {
2651 unsigned int pinctl = AC_PINCTL_IN_EN;
2652 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2653 pinctl |= stac92xx_get_vref(codec, nid);
2654 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2655 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002656 }
Matt Porter8b657272006-10-26 17:12:59 +02002657 if (spec->num_dmics > 0)
2658 for (i = 0; i < spec->num_dmics; i++)
2659 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2660 AC_PINCTL_IN_EN);
2661
Takashi Iwai82bc9552006-03-21 11:24:42 +01002662 if (cfg->dig_out_pin)
2663 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2664 AC_PINCTL_OUT_EN);
2665 if (cfg->dig_in_pin)
2666 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2667 AC_PINCTL_IN_EN);
2668
Sam Revitch62fe78e2006-05-10 15:09:17 +02002669 if (spec->gpio_mute) {
2670 stac922x_gpio_mute(codec, 0, 0);
2671 stac922x_gpio_mute(codec, 1, 0);
2672 }
2673
Mattc7d4b2f2005-06-27 14:59:41 +02002674 return 0;
2675}
2676
Matt2f2f4252005-04-13 14:45:30 +02002677static void stac92xx_free(struct hda_codec *codec)
2678{
Mattc7d4b2f2005-06-27 14:59:41 +02002679 struct sigmatel_spec *spec = codec->spec;
2680 int i;
2681
2682 if (! spec)
2683 return;
2684
2685 if (spec->kctl_alloc) {
2686 for (i = 0; i < spec->num_kctl_used; i++)
2687 kfree(spec->kctl_alloc[i].name);
2688 kfree(spec->kctl_alloc);
2689 }
2690
Richard Fish11b44bb2006-08-23 18:31:34 +02002691 if (spec->bios_pin_configs)
2692 kfree(spec->bios_pin_configs);
2693
Mattc7d4b2f2005-06-27 14:59:41 +02002694 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002695}
2696
Matt4e550962005-07-04 17:51:39 +02002697static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2698 unsigned int flag)
2699{
2700 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2701 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002702
Takashi Iwaif9acba42007-05-29 18:01:06 +02002703 if (pin_ctl & AC_PINCTL_IN_EN) {
2704 /*
2705 * we need to check the current set-up direction of
2706 * shared input pins since they can be switched via
2707 * "xxx as Output" mixer switch
2708 */
2709 struct sigmatel_spec *spec = codec->spec;
2710 struct auto_pin_cfg *cfg = &spec->autocfg;
2711 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2712 spec->line_switch) ||
2713 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2714 spec->mic_switch))
2715 return;
2716 }
2717
Steve Longerbeam7b043892007-05-03 20:50:03 +02002718 /* if setting pin direction bits, clear the current
2719 direction bits first */
2720 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2721 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2722
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002723 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002724 AC_VERB_SET_PIN_WIDGET_CONTROL,
2725 pin_ctl | flag);
2726}
2727
2728static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2729 unsigned int flag)
2730{
2731 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2732 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002733 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002734 AC_VERB_SET_PIN_WIDGET_CONTROL,
2735 pin_ctl & ~flag);
2736}
2737
Jiang Zhe40c1d302007-11-12 13:05:16 +01002738static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02002739{
2740 if (!nid)
2741 return 0;
2742 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01002743 & (1 << 31)) {
2744 unsigned int pinctl;
2745 pinctl = snd_hda_codec_read(codec, nid, 0,
2746 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2747 if (pinctl & AC_PINCTL_IN_EN)
2748 return 0; /* mic- or line-input */
2749 else
2750 return 1; /* HP-output */
2751 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002752 return 0;
2753}
2754
2755static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02002756{
2757 struct sigmatel_spec *spec = codec->spec;
2758 struct auto_pin_cfg *cfg = &spec->autocfg;
2759 int i, presence;
2760
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002761 presence = 0;
2762 for (i = 0; i < cfg->hp_outs; i++) {
Jiang Zhe40c1d302007-11-12 13:05:16 +01002763 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwai314634b2006-09-21 11:56:18 +02002764 if (presence)
2765 break;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002766 }
Matt4e550962005-07-04 17:51:39 +02002767
2768 if (presence) {
2769 /* disable lineouts, enable hp */
2770 for (i = 0; i < cfg->line_outs; i++)
2771 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
2772 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002773 for (i = 0; i < cfg->speaker_outs; i++)
2774 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
2775 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002776 } else {
2777 /* enable lineouts, disable hp */
2778 for (i = 0; i < cfg->line_outs; i++)
2779 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
2780 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002781 for (i = 0; i < cfg->speaker_outs; i++)
2782 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
2783 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002784 }
2785}
2786
Takashi Iwai314634b2006-09-21 11:56:18 +02002787static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
2788{
2789 switch (res >> 26) {
2790 case STAC_HP_EVENT:
2791 stac92xx_hp_detect(codec, res);
2792 break;
2793 }
2794}
2795
Takashi Iwaicb53c622007-08-10 17:21:45 +02002796#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002797static int stac92xx_resume(struct hda_codec *codec)
2798{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002799 struct sigmatel_spec *spec = codec->spec;
2800
Richard Fish11b44bb2006-08-23 18:31:34 +02002801 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002802 snd_hda_sequence_write(codec, spec->init);
2803 if (spec->gpio_mute) {
2804 stac922x_gpio_mute(codec, 0, 0);
2805 stac922x_gpio_mute(codec, 1, 0);
2806 }
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002807 snd_hda_codec_resume_amp(codec);
2808 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002809 /* invoke unsolicited event to reset the HP state */
2810 if (spec->hp_detect)
2811 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02002812 return 0;
2813}
2814#endif
2815
Matt2f2f4252005-04-13 14:45:30 +02002816static struct hda_codec_ops stac92xx_patch_ops = {
2817 .build_controls = stac92xx_build_controls,
2818 .build_pcms = stac92xx_build_pcms,
2819 .init = stac92xx_init,
2820 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02002821 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002822#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002823 .resume = stac92xx_resume,
2824#endif
Matt2f2f4252005-04-13 14:45:30 +02002825};
2826
2827static int patch_stac9200(struct hda_codec *codec)
2828{
2829 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002830 int err;
Matt2f2f4252005-04-13 14:45:30 +02002831
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002832 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02002833 if (spec == NULL)
2834 return -ENOMEM;
2835
2836 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002837 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002838 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002839 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
2840 stac9200_models,
2841 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02002842 if (spec->board_config < 0) {
2843 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
2844 err = stac92xx_save_bios_config_regs(codec);
2845 if (err < 0) {
2846 stac92xx_free(codec);
2847 return err;
2848 }
2849 spec->pin_configs = spec->bios_pin_configs;
2850 } else {
Matt Porter403d1942005-11-29 15:00:51 +01002851 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
2852 stac92xx_set_config_regs(codec);
2853 }
Matt2f2f4252005-04-13 14:45:30 +02002854
2855 spec->multiout.max_channels = 2;
2856 spec->multiout.num_dacs = 1;
2857 spec->multiout.dac_nids = stac9200_dac_nids;
2858 spec->adc_nids = stac9200_adc_nids;
2859 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02002860 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02002861 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002862 spec->num_adcs = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002863
Takashi Iwai1194b5b2007-10-10 10:04:26 +02002864 if (spec->board_config == STAC_9200_GATEWAY)
2865 spec->init = stac9200_eapd_init;
2866 else
2867 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02002868 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02002869
2870 err = stac9200_parse_auto_config(codec);
2871 if (err < 0) {
2872 stac92xx_free(codec);
2873 return err;
2874 }
Matt2f2f4252005-04-13 14:45:30 +02002875
2876 codec->patch_ops = stac92xx_patch_ops;
2877
2878 return 0;
2879}
2880
Tobin Davis8e21c342007-01-08 11:04:17 +01002881static int patch_stac925x(struct hda_codec *codec)
2882{
2883 struct sigmatel_spec *spec;
2884 int err;
2885
2886 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2887 if (spec == NULL)
2888 return -ENOMEM;
2889
2890 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002891 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01002892 spec->pin_nids = stac925x_pin_nids;
2893 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
2894 stac925x_models,
2895 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002896 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01002897 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02002898 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
2899 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01002900 err = stac92xx_save_bios_config_regs(codec);
2901 if (err < 0) {
2902 stac92xx_free(codec);
2903 return err;
2904 }
2905 spec->pin_configs = spec->bios_pin_configs;
2906 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
2907 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
2908 stac92xx_set_config_regs(codec);
2909 }
2910
2911 spec->multiout.max_channels = 2;
2912 spec->multiout.num_dacs = 1;
2913 spec->multiout.dac_nids = stac925x_dac_nids;
2914 spec->adc_nids = stac925x_adc_nids;
2915 spec->mux_nids = stac925x_mux_nids;
2916 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002917 spec->num_adcs = 1;
Tobin Davis2c11f952007-05-17 09:36:34 +02002918 switch (codec->vendor_id) {
2919 case 0x83847632: /* STAC9202 */
2920 case 0x83847633: /* STAC9202D */
2921 case 0x83847636: /* STAC9251 */
2922 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02002923 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02002924 spec->dmic_nids = stac925x_dmic_nids;
2925 break;
2926 default:
2927 spec->num_dmics = 0;
2928 break;
2929 }
Tobin Davis8e21c342007-01-08 11:04:17 +01002930
2931 spec->init = stac925x_core_init;
2932 spec->mixer = stac925x_mixer;
2933
2934 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01002935 if (!err) {
2936 if (spec->board_config < 0) {
2937 printk(KERN_WARNING "hda_codec: No auto-config is "
2938 "available, default to model=ref\n");
2939 spec->board_config = STAC_925x_REF;
2940 goto again;
2941 }
2942 err = -EINVAL;
2943 }
Tobin Davis8e21c342007-01-08 11:04:17 +01002944 if (err < 0) {
2945 stac92xx_free(codec);
2946 return err;
2947 }
2948
2949 codec->patch_ops = stac92xx_patch_ops;
2950
2951 return 0;
2952}
2953
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002954static struct hda_input_mux stac92hd73xx_dmux = {
2955 .num_items = 4,
2956 .items = {
2957 { "Analog Inputs", 0x0b },
2958 { "CD", 0x08 },
2959 { "Digital Mic 1", 0x09 },
2960 { "Digital Mic 2", 0x0a },
2961 }
2962};
2963
2964static int patch_stac92hd73xx(struct hda_codec *codec)
2965{
2966 struct sigmatel_spec *spec;
2967 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
2968 int err = 0;
2969
2970 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2971 if (spec == NULL)
2972 return -ENOMEM;
2973
2974 codec->spec = spec;
2975 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
2976 spec->pin_nids = stac92hd73xx_pin_nids;
2977 spec->board_config = snd_hda_check_board_config(codec,
2978 STAC_92HD73XX_MODELS,
2979 stac92hd73xx_models,
2980 stac92hd73xx_cfg_tbl);
2981again:
2982 if (spec->board_config < 0) {
2983 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
2984 " STAC92HD73XX, using BIOS defaults\n");
2985 err = stac92xx_save_bios_config_regs(codec);
2986 if (err < 0) {
2987 stac92xx_free(codec);
2988 return err;
2989 }
2990 spec->pin_configs = spec->bios_pin_configs;
2991 } else {
2992 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
2993 stac92xx_set_config_regs(codec);
2994 }
2995
2996 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
2997 conn, STAC92HD73_DAC_COUNT + 2) - 1;
2998
2999 if (spec->multiout.num_dacs < 0) {
3000 printk(KERN_WARNING "hda_codec: Could not determine "
3001 "number of channels defaulting to DAC count\n");
3002 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3003 }
3004
3005 switch (spec->multiout.num_dacs) {
3006 case 0x3: /* 6 Channel */
3007 spec->mixer = stac92hd73xx_6ch_mixer;
3008 spec->init = stac92hd73xx_6ch_core_init;
3009 break;
3010 case 0x4: /* 8 Channel */
3011 spec->multiout.hp_nid = 0x18;
3012 spec->mixer = stac92hd73xx_8ch_mixer;
3013 spec->init = stac92hd73xx_8ch_core_init;
3014 break;
3015 case 0x5: /* 10 Channel */
3016 spec->multiout.hp_nid = 0x19;
3017 spec->mixer = stac92hd73xx_10ch_mixer;
3018 spec->init = stac92hd73xx_10ch_core_init;
3019 };
3020
3021 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3022 spec->aloopback_mask = 0x01;
3023 spec->aloopback_shift = 8;
3024
3025 spec->mux_nids = stac92hd73xx_mux_nids;
3026 spec->adc_nids = stac92hd73xx_adc_nids;
3027 spec->dmic_nids = stac92hd73xx_dmic_nids;
3028 spec->dmux_nids = stac92hd73xx_dmux_nids;
3029
3030 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3031 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3032 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3033 spec->dinput_mux = &stac92hd73xx_dmux;
3034 /* GPIO0 High = Enable EAPD */
3035 spec->gpio_mask = spec->gpio_data = 0x000001;
3036 stac92xx_enable_gpio_mask(codec);
3037
3038 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3039
3040 if (!err) {
3041 if (spec->board_config < 0) {
3042 printk(KERN_WARNING "hda_codec: No auto-config is "
3043 "available, default to model=ref\n");
3044 spec->board_config = STAC_92HD73XX_REF;
3045 goto again;
3046 }
3047 err = -EINVAL;
3048 }
3049
3050 if (err < 0) {
3051 stac92xx_free(codec);
3052 return err;
3053 }
3054
3055 codec->patch_ops = stac92xx_patch_ops;
3056
3057 return 0;
3058}
3059
Matthew Ranostaye035b842007-11-06 11:53:55 +01003060static int patch_stac92hd71bxx(struct hda_codec *codec)
3061{
3062 struct sigmatel_spec *spec;
3063 int err = 0;
3064
3065 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3066 if (spec == NULL)
3067 return -ENOMEM;
3068
3069 codec->spec = spec;
3070 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3071 spec->pin_nids = stac92hd71bxx_pin_nids;
3072 spec->board_config = snd_hda_check_board_config(codec,
3073 STAC_92HD71BXX_MODELS,
3074 stac92hd71bxx_models,
3075 stac92hd71bxx_cfg_tbl);
3076again:
3077 if (spec->board_config < 0) {
3078 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3079 " STAC92HD71BXX, using BIOS defaults\n");
3080 err = stac92xx_save_bios_config_regs(codec);
3081 if (err < 0) {
3082 stac92xx_free(codec);
3083 return err;
3084 }
3085 spec->pin_configs = spec->bios_pin_configs;
3086 } else {
3087 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3088 stac92xx_set_config_regs(codec);
3089 }
3090
3091 spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
3092 stac92xx_enable_gpio_mask(codec);
3093
3094 spec->init = stac92hd71bxx_core_init;
3095 spec->mixer = stac92hd71bxx_mixer;
3096
3097 spec->mux_nids = stac92hd71bxx_mux_nids;
3098 spec->adc_nids = stac92hd71bxx_adc_nids;
3099 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003100 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003101
3102 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3103 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3104 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
3105
3106 spec->multiout.num_dacs = 2;
3107 spec->multiout.hp_nid = 0x11;
3108 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3109
3110 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3111 if (!err) {
3112 if (spec->board_config < 0) {
3113 printk(KERN_WARNING "hda_codec: No auto-config is "
3114 "available, default to model=ref\n");
3115 spec->board_config = STAC_92HD71BXX_REF;
3116 goto again;
3117 }
3118 err = -EINVAL;
3119 }
3120
3121 if (err < 0) {
3122 stac92xx_free(codec);
3123 return err;
3124 }
3125
3126 codec->patch_ops = stac92xx_patch_ops;
3127
3128 return 0;
3129};
3130
Matt2f2f4252005-04-13 14:45:30 +02003131static int patch_stac922x(struct hda_codec *codec)
3132{
3133 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003134 int err;
Matt2f2f4252005-04-13 14:45:30 +02003135
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003136 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003137 if (spec == NULL)
3138 return -ENOMEM;
3139
3140 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003141 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003142 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003143 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3144 stac922x_models,
3145 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003146 if (spec->board_config == STAC_INTEL_MAC_V3) {
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003147 spec->gpio_mute = 1;
3148 /* Intel Macs have all same PCI SSID, so we need to check
3149 * codec SSID to distinguish the exact models
3150 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003151 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003152 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003153
3154 case 0x106b0800:
3155 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003156 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003157 case 0x106b0600:
3158 case 0x106b0700:
3159 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003160 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003161 case 0x106b0e00:
3162 case 0x106b0f00:
3163 case 0x106b1600:
3164 case 0x106b1700:
3165 case 0x106b0200:
3166 case 0x106b1e00:
3167 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003168 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003169 case 0x106b1a00:
3170 case 0x00000100:
3171 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003172 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003173 case 0x106b0a00:
3174 case 0x106b2200:
3175 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003176 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003177 }
3178 }
3179
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003180 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003181 if (spec->board_config < 0) {
3182 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3183 "using BIOS defaults\n");
3184 err = stac92xx_save_bios_config_regs(codec);
3185 if (err < 0) {
3186 stac92xx_free(codec);
3187 return err;
3188 }
3189 spec->pin_configs = spec->bios_pin_configs;
3190 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003191 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3192 stac92xx_set_config_regs(codec);
3193 }
Matt2f2f4252005-04-13 14:45:30 +02003194
Matt2f2f4252005-04-13 14:45:30 +02003195 spec->adc_nids = stac922x_adc_nids;
3196 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003197 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003198 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003199 spec->num_dmics = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003200
3201 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003202 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003203
3204 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003205
Matt Porter3cc08dc2006-01-23 15:27:49 +01003206 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003207 if (!err) {
3208 if (spec->board_config < 0) {
3209 printk(KERN_WARNING "hda_codec: No auto-config is "
3210 "available, default to model=ref\n");
3211 spec->board_config = STAC_D945_REF;
3212 goto again;
3213 }
3214 err = -EINVAL;
3215 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003216 if (err < 0) {
3217 stac92xx_free(codec);
3218 return err;
3219 }
3220
3221 codec->patch_ops = stac92xx_patch_ops;
3222
Takashi Iwai807a46362007-05-29 19:01:37 +02003223 /* Fix Mux capture level; max to 2 */
3224 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3225 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3226 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3227 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3228 (0 << AC_AMPCAP_MUTE_SHIFT));
3229
Matt Porter3cc08dc2006-01-23 15:27:49 +01003230 return 0;
3231}
3232
3233static int patch_stac927x(struct hda_codec *codec)
3234{
3235 struct sigmatel_spec *spec;
3236 int err;
3237
3238 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3239 if (spec == NULL)
3240 return -ENOMEM;
3241
3242 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003243 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003244 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003245 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3246 stac927x_models,
3247 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003248 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003249 if (spec->board_config < 0) {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003250 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003251 err = stac92xx_save_bios_config_regs(codec);
3252 if (err < 0) {
3253 stac92xx_free(codec);
3254 return err;
3255 }
3256 spec->pin_configs = spec->bios_pin_configs;
3257 } else if (stac927x_brd_tbl[spec->board_config] != NULL) {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003258 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3259 stac92xx_set_config_regs(codec);
3260 }
3261
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003262 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003263 case STAC_D965_3ST:
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003264 spec->adc_nids = stac927x_adc_nids;
3265 spec->mux_nids = stac927x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003266 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003267 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
Tobin Davis93ed1502006-09-01 21:03:12 +02003268 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003269 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003270 break;
Tobin Davis93ed1502006-09-01 21:03:12 +02003271 case STAC_D965_5ST:
3272 spec->adc_nids = stac927x_adc_nids;
3273 spec->mux_nids = stac927x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003274 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003275 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
Tobin Davis93ed1502006-09-01 21:03:12 +02003276 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003277 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003278 break;
3279 default:
3280 spec->adc_nids = stac927x_adc_nids;
3281 spec->mux_nids = stac927x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003282 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003283 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003284 spec->init = stac927x_core_init;
3285 spec->mixer = stac927x_mixer;
3286 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003287
Matthew Ranostay7f168592007-10-18 17:38:17 +02003288 switch (codec->subsystem_id) {
Matthew Ranostayb222fe52007-11-07 15:54:45 +01003289 case 0x10280242: /* STAC 9228 */
3290 case 0x102801f3:
3291 case 0x1028020A:
3292 case 0x10280209:
Matthew Ranostay7f168592007-10-18 17:38:17 +02003293 spec->dmic_nids = stac927x_dmic_nids;
3294 spec->num_dmics = STAC927X_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003295 spec->dmux_nids = stac927x_dmux_nids;
Matthew Ranostayf1f208d2007-11-05 15:30:13 +01003296
3297 /* Enable DMIC0 */
3298 stac92xx_set_config_reg(codec, 0x13, 0x90a60040);
3299
3300 /* GPIO2 High = Enable EAPD */
3301 spec->gpio_mask = spec->gpio_data = 0x00000004;
Matthew Ranostay7f168592007-10-18 17:38:17 +02003302 break;
3303 default:
Matthew Ranostayf1f208d2007-11-05 15:30:13 +01003304 spec->num_dmics = 0;
3305
3306 /* GPIO0 High = Enable EAPD */
3307 spec->gpio_mask = spec->gpio_data = 0x00000001;
Matthew Ranostay7f168592007-10-18 17:38:17 +02003308 }
3309
Matt Porter3cc08dc2006-01-23 15:27:49 +01003310 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003311 spec->aloopback_mask = 0x40;
3312 spec->aloopback_shift = 0;
Takashi Iwai82599802007-07-31 15:56:24 +02003313 stac92xx_enable_gpio_mask(codec);
Matthew Ranostay92a22be2007-06-19 16:48:28 +02003314
Matt Porter3cc08dc2006-01-23 15:27:49 +01003315 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003316 if (!err) {
3317 if (spec->board_config < 0) {
3318 printk(KERN_WARNING "hda_codec: No auto-config is "
3319 "available, default to model=ref\n");
3320 spec->board_config = STAC_D965_REF;
3321 goto again;
3322 }
3323 err = -EINVAL;
3324 }
Mattc7d4b2f2005-06-27 14:59:41 +02003325 if (err < 0) {
3326 stac92xx_free(codec);
3327 return err;
3328 }
Matt2f2f4252005-04-13 14:45:30 +02003329
3330 codec->patch_ops = stac92xx_patch_ops;
3331
3332 return 0;
3333}
3334
Matt Porterf3302a52006-07-31 12:49:34 +02003335static int patch_stac9205(struct hda_codec *codec)
3336{
3337 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003338 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003339
3340 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3341 if (spec == NULL)
3342 return -ENOMEM;
3343
3344 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003345 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003346 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003347 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3348 stac9205_models,
3349 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003350 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003351 if (spec->board_config < 0) {
3352 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3353 err = stac92xx_save_bios_config_regs(codec);
3354 if (err < 0) {
3355 stac92xx_free(codec);
3356 return err;
3357 }
3358 spec->pin_configs = spec->bios_pin_configs;
3359 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003360 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3361 stac92xx_set_config_regs(codec);
3362 }
3363
3364 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003365 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003366 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003367 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003368 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003369 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003370 spec->dmux_nids = stac9205_dmux_nids;
Matt Porterf3302a52006-07-31 12:49:34 +02003371
3372 spec->init = stac9205_core_init;
3373 spec->mixer = stac9205_mixer;
3374
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003375 spec->aloopback_mask = 0x40;
3376 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003377 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003378
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003379 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003380 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003381 /* Enable SPDIF in/out */
3382 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3383 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003384
Takashi Iwai82599802007-07-31 15:56:24 +02003385 spec->gpio_mask = 0x00000007; /* GPIO0-2 */
Matthew Ranostay87d48362007-07-17 11:52:24 +02003386 /* GPIO0 High = EAPD, GPIO1 Low = DRM,
3387 * GPIO2 High = Headphone Mute
3388 */
Takashi Iwai82599802007-07-31 15:56:24 +02003389 spec->gpio_data = 0x00000005;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003390 break;
3391 default:
3392 /* GPIO0 High = EAPD */
3393 spec->gpio_mask = spec->gpio_data = 0x00000001;
3394 break;
3395 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003396
Takashi Iwai82599802007-07-31 15:56:24 +02003397 stac92xx_enable_gpio_mask(codec);
Matt Porterf3302a52006-07-31 12:49:34 +02003398 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003399 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_9205_REF;
3404 goto again;
3405 }
3406 err = -EINVAL;
3407 }
Matt Porterf3302a52006-07-31 12:49:34 +02003408 if (err < 0) {
3409 stac92xx_free(codec);
3410 return err;
3411 }
3412
3413 codec->patch_ops = stac92xx_patch_ops;
3414
3415 return 0;
3416}
3417
Matt2f2f4252005-04-13 14:45:30 +02003418/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003419 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003420 */
3421
Guillaume Munch99ccc562006-08-16 19:35:12 +02003422/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003423static hda_nid_t vaio_dacs[] = { 0x2 };
3424#define VAIO_HP_DAC 0x5
3425static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3426static hda_nid_t vaio_mux_nids[] = { 0x15 };
3427
3428static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003429 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003430 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003431 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003432 { "Mic Jack", 0x1 },
3433 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003434 { "PCM", 0x3 },
3435 }
3436};
3437
3438static struct hda_verb vaio_init[] = {
3439 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003440 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003441 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3442 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3443 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3444 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003445 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003446 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3447 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3448 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3449 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3450 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3451 {}
3452};
3453
Guillaume Munch6d859062006-08-22 17:15:47 +02003454static struct hda_verb vaio_ar_init[] = {
3455 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3456 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3457 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3458 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3459/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3460 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003461 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003462 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3463 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3464/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3465 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3467 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3468 {}
3469};
3470
Takashi Iwaidb064e52006-03-16 16:04:58 +01003471/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003472static struct hda_bind_ctls vaio_bind_master_vol = {
3473 .ops = &snd_hda_bind_vol,
3474 .values = {
3475 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3476 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3477 0
3478 },
3479};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003480
3481/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003482static struct hda_bind_ctls vaio_bind_master_sw = {
3483 .ops = &snd_hda_bind_sw,
3484 .values = {
3485 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3486 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3487 0,
3488 },
3489};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003490
3491static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003492 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3493 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003494 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3495 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3496 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3497 {
3498 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3499 .name = "Capture Source",
3500 .count = 1,
3501 .info = stac92xx_mux_enum_info,
3502 .get = stac92xx_mux_enum_get,
3503 .put = stac92xx_mux_enum_put,
3504 },
3505 {}
3506};
3507
Guillaume Munch6d859062006-08-22 17:15:47 +02003508static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003509 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3510 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003511 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3512 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3513 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3514 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3515 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3516 {
3517 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3518 .name = "Capture Source",
3519 .count = 1,
3520 .info = stac92xx_mux_enum_info,
3521 .get = stac92xx_mux_enum_get,
3522 .put = stac92xx_mux_enum_put,
3523 },
3524 {}
3525};
3526
3527static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003528 .build_controls = stac92xx_build_controls,
3529 .build_pcms = stac92xx_build_pcms,
3530 .init = stac92xx_init,
3531 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003532#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003533 .resume = stac92xx_resume,
3534#endif
3535};
3536
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003537static int stac9872_vaio_init(struct hda_codec *codec)
3538{
3539 int err;
3540
3541 err = stac92xx_init(codec);
3542 if (err < 0)
3543 return err;
3544 if (codec->patch_ops.unsol_event)
3545 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3546 return 0;
3547}
3548
3549static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3550{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003551 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003552 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3553 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3554 } else {
3555 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3556 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3557 }
3558}
3559
3560static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3561{
3562 switch (res >> 26) {
3563 case STAC_HP_EVENT:
3564 stac9872_vaio_hp_detect(codec, res);
3565 break;
3566 }
3567}
3568
3569static struct hda_codec_ops stac9872_vaio_patch_ops = {
3570 .build_controls = stac92xx_build_controls,
3571 .build_pcms = stac92xx_build_pcms,
3572 .init = stac9872_vaio_init,
3573 .free = stac92xx_free,
3574 .unsol_event = stac9872_vaio_unsol_event,
3575#ifdef CONFIG_PM
3576 .resume = stac92xx_resume,
3577#endif
3578};
3579
Guillaume Munch6d859062006-08-22 17:15:47 +02003580enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3581 CXD9872RD_VAIO,
3582 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3583 STAC9872AK_VAIO,
3584 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3585 STAC9872K_VAIO,
3586 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003587 CXD9872AKD_VAIO,
3588 STAC_9872_MODELS,
3589};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003590
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003591static const char *stac9872_models[STAC_9872_MODELS] = {
3592 [CXD9872RD_VAIO] = "vaio",
3593 [CXD9872AKD_VAIO] = "vaio-ar",
3594};
3595
3596static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3597 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3598 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3599 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003600 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003601 {}
3602};
3603
Guillaume Munch6d859062006-08-22 17:15:47 +02003604static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003605{
3606 struct sigmatel_spec *spec;
3607 int board_config;
3608
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003609 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3610 stac9872_models,
3611 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003612 if (board_config < 0)
3613 /* unknown config, let generic-parser do its job... */
3614 return snd_hda_parse_generic_codec(codec);
3615
3616 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3617 if (spec == NULL)
3618 return -ENOMEM;
3619
3620 codec->spec = spec;
3621 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003622 case CXD9872RD_VAIO:
3623 case STAC9872AK_VAIO:
3624 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003625 spec->mixer = vaio_mixer;
3626 spec->init = vaio_init;
3627 spec->multiout.max_channels = 2;
3628 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3629 spec->multiout.dac_nids = vaio_dacs;
3630 spec->multiout.hp_nid = VAIO_HP_DAC;
3631 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3632 spec->adc_nids = vaio_adcs;
3633 spec->input_mux = &vaio_mux;
3634 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003635 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003636 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003637
3638 case CXD9872AKD_VAIO:
3639 spec->mixer = vaio_ar_mixer;
3640 spec->init = vaio_ar_init;
3641 spec->multiout.max_channels = 2;
3642 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3643 spec->multiout.dac_nids = vaio_dacs;
3644 spec->multiout.hp_nid = VAIO_HP_DAC;
3645 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3646 spec->adc_nids = vaio_adcs;
3647 spec->input_mux = &vaio_mux;
3648 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003649 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003650 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003651 }
3652
Takashi Iwaidb064e52006-03-16 16:04:58 +01003653 return 0;
3654}
3655
3656
3657/*
Matt2f2f4252005-04-13 14:45:30 +02003658 * patch entries
3659 */
3660struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3661 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3662 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3663 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3664 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3665 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3666 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3667 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003668 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3669 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3670 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3671 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3672 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
3673 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01003674 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
3675 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
3676 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
3677 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
3678 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
3679 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
3680 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
3681 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
3682 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
3683 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01003684 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
3685 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
3686 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
3687 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
3688 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
3689 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02003690 /* The following does not take into account .id=0x83847661 when subsys =
3691 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
3692 * currently not fully supported.
3693 */
3694 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
3695 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
3696 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02003697 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
3698 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
3699 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
3700 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
3701 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
3702 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
3703 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
3704 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003705 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
3706 { .id = 0x111d7675, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye035b842007-11-06 11:53:55 +01003707 { .id = 0x111d76b0, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02003708 {} /* terminator */
3709};