blob: c3496de387c59b3a35ee71ee7fe5b4300c0687b8 [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
35
Matt4e550962005-07-04 17:51:39 +020036#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010037#define STAC_PWR_EVENT 0x20
38#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020039
Takashi Iwaif5fcc132006-11-24 17:07:44 +010040enum {
41 STAC_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020042 STAC_9200_DELL_D21,
43 STAC_9200_DELL_D22,
44 STAC_9200_DELL_D23,
45 STAC_9200_DELL_M21,
46 STAC_9200_DELL_M22,
47 STAC_9200_DELL_M23,
48 STAC_9200_DELL_M24,
49 STAC_9200_DELL_M25,
50 STAC_9200_DELL_M26,
51 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020052 STAC_9200_GATEWAY,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010053 STAC_9200_MODELS
54};
55
56enum {
57 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020058 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020059 STAC_9205_DELL_M43,
60 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010061 STAC_9205_MODELS
62};
63
64enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010065 STAC_92HD73XX_REF,
66 STAC_92HD73XX_MODELS
67};
68
69enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010070 STAC_92HD71BXX_REF,
71 STAC_92HD71BXX_MODELS
72};
73
74enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010075 STAC_925x_REF,
76 STAC_M2_2,
77 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020078 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010079 STAC_925x_MODELS
80};
81
82enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010083 STAC_D945_REF,
84 STAC_D945GTP3,
85 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020086 STAC_INTEL_MAC_V1,
87 STAC_INTEL_MAC_V2,
88 STAC_INTEL_MAC_V3,
89 STAC_INTEL_MAC_V4,
90 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020091 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010092 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010093 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010094 STAC_MACBOOK_PRO_V1,
95 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +020096 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +020097 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020098 STAC_922X_DELL_D81,
99 STAC_922X_DELL_D82,
100 STAC_922X_DELL_M81,
101 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100102 STAC_922X_MODELS
103};
104
105enum {
106 STAC_D965_REF,
107 STAC_D965_3ST,
108 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200109 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100110 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100111 STAC_927X_MODELS
112};
Matt Porter403d1942005-11-29 15:00:51 +0100113
Matt2f2f4252005-04-13 14:45:30 +0200114struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100115 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200116 unsigned int num_mixers;
117
Matt Porter403d1942005-11-29 15:00:51 +0100118 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200119 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100120 unsigned int line_switch: 1;
121 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100122 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100123 unsigned int hp_detect: 1;
Sam Revitch62fe78e2006-05-10 15:09:17 +0200124 unsigned int gpio_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200125
Takashi Iwai82599802007-07-31 15:56:24 +0200126 unsigned int gpio_mask, gpio_data;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100127 unsigned char aloopback_mask;
128 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200129
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100130 /* power management */
131 unsigned int num_pwrs;
132 hda_nid_t *pwr_nids;
133
Matt2f2f4252005-04-13 14:45:30 +0200134 /* playback */
135 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100136 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200137
138 /* capture */
139 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200140 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200141 hda_nid_t *mux_nids;
142 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200143 hda_nid_t *dmic_nids;
144 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100145 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100146 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200147 hda_nid_t dig_in_nid;
Matt2f2f4252005-04-13 14:45:30 +0200148
Matt2f2f4252005-04-13 14:45:30 +0200149 /* pin widgets */
150 hda_nid_t *pin_nids;
151 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200152 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200153 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200154
155 /* codec specific stuff */
156 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100157 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200158
159 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200160 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100161 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200162 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100163 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200164
Matt Porter403d1942005-11-29 15:00:51 +0100165 /* i/o switches */
166 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200167 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200168 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200169
Mattc7d4b2f2005-06-27 14:59:41 +0200170 struct hda_pcm pcm_rec[2]; /* PCM information */
171
172 /* dynamic controls and input_mux */
173 struct auto_pin_cfg autocfg;
174 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100175 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200176 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200177 struct hda_input_mux private_imux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100178
179 /* virtual master */
180 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200181};
182
183static hda_nid_t stac9200_adc_nids[1] = {
184 0x03,
185};
186
187static hda_nid_t stac9200_mux_nids[1] = {
188 0x0c,
189};
190
191static hda_nid_t stac9200_dac_nids[1] = {
192 0x02,
193};
194
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100195static hda_nid_t stac92hd73xx_pwr_nids[8] = {
196 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
197 0x0f, 0x10, 0x11
198};
199
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100200static hda_nid_t stac92hd73xx_adc_nids[2] = {
201 0x1a, 0x1b
202};
203
204#define STAC92HD73XX_NUM_DMICS 2
205static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
206 0x13, 0x14, 0
207};
208
209#define STAC92HD73_DAC_COUNT 5
210static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
211 0x15, 0x16, 0x17, 0x18, 0x19,
212};
213
214static hda_nid_t stac92hd73xx_mux_nids[4] = {
215 0x28, 0x29, 0x2a, 0x2b,
216};
217
218static hda_nid_t stac92hd73xx_dmux_nids[2] = {
219 0x20, 0x21,
220};
221
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100222static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
223 0x0a, 0x0d, 0x0f
224};
225
Matthew Ranostaye035b842007-11-06 11:53:55 +0100226static hda_nid_t stac92hd71bxx_adc_nids[2] = {
227 0x12, 0x13,
228};
229
230static hda_nid_t stac92hd71bxx_mux_nids[2] = {
231 0x1a, 0x1b
232};
233
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100234static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
235 0x1c,
236};
237
Matthew Ranostaye035b842007-11-06 11:53:55 +0100238static hda_nid_t stac92hd71bxx_dac_nids[2] = {
239 0x10, /*0x11, */
240};
241
242#define STAC92HD71BXX_NUM_DMICS 2
243static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
244 0x18, 0x19, 0
245};
246
Tobin Davis8e21c342007-01-08 11:04:17 +0100247static hda_nid_t stac925x_adc_nids[1] = {
248 0x03,
249};
250
251static hda_nid_t stac925x_mux_nids[1] = {
252 0x0f,
253};
254
255static hda_nid_t stac925x_dac_nids[1] = {
256 0x02,
257};
258
Takashi Iwaif6e98522007-10-16 14:27:04 +0200259#define STAC925X_NUM_DMICS 1
260static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
261 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200262};
263
Takashi Iwai1697055e2007-12-18 18:05:52 +0100264static hda_nid_t stac925x_dmux_nids[1] = {
265 0x14,
266};
267
Matt2f2f4252005-04-13 14:45:30 +0200268static hda_nid_t stac922x_adc_nids[2] = {
269 0x06, 0x07,
270};
271
272static hda_nid_t stac922x_mux_nids[2] = {
273 0x12, 0x13,
274};
275
Matt Porter3cc08dc2006-01-23 15:27:49 +0100276static hda_nid_t stac927x_adc_nids[3] = {
277 0x07, 0x08, 0x09
278};
279
280static hda_nid_t stac927x_mux_nids[3] = {
281 0x15, 0x16, 0x17
282};
283
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100284static hda_nid_t stac927x_dmux_nids[1] = {
285 0x1b,
286};
287
Matthew Ranostay7f168592007-10-18 17:38:17 +0200288#define STAC927X_NUM_DMICS 2
289static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
290 0x13, 0x14, 0
291};
292
Matt Porterf3302a52006-07-31 12:49:34 +0200293static hda_nid_t stac9205_adc_nids[2] = {
294 0x12, 0x13
295};
296
297static hda_nid_t stac9205_mux_nids[2] = {
298 0x19, 0x1a
299};
300
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100301static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100302 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100303};
304
Takashi Iwaif6e98522007-10-16 14:27:04 +0200305#define STAC9205_NUM_DMICS 2
306static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
307 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200308};
309
Mattc7d4b2f2005-06-27 14:59:41 +0200310static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200311 0x08, 0x09, 0x0d, 0x0e,
312 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200313};
314
Tobin Davis8e21c342007-01-08 11:04:17 +0100315static hda_nid_t stac925x_pin_nids[8] = {
316 0x07, 0x08, 0x0a, 0x0b,
317 0x0c, 0x0d, 0x10, 0x11,
318};
319
Matt2f2f4252005-04-13 14:45:30 +0200320static hda_nid_t stac922x_pin_nids[10] = {
321 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
322 0x0f, 0x10, 0x11, 0x15, 0x1b,
323};
324
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100325static hda_nid_t stac92hd73xx_pin_nids[12] = {
326 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
327 0x0f, 0x10, 0x11, 0x12, 0x13,
328 0x14, 0x22
329};
330
Matthew Ranostaye035b842007-11-06 11:53:55 +0100331static hda_nid_t stac92hd71bxx_pin_nids[10] = {
332 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
333 0x0f, 0x14, 0x18, 0x19, 0x1e,
334};
335
Matt Porter3cc08dc2006-01-23 15:27:49 +0100336static hda_nid_t stac927x_pin_nids[14] = {
337 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
338 0x0f, 0x10, 0x11, 0x12, 0x13,
339 0x14, 0x21, 0x22, 0x23,
340};
341
Matt Porterf3302a52006-07-31 12:49:34 +0200342static hda_nid_t stac9205_pin_nids[12] = {
343 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
344 0x0f, 0x14, 0x16, 0x17, 0x18,
345 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200346};
347
Matt Porter8b657272006-10-26 17:12:59 +0200348static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
349 struct snd_ctl_elem_info *uinfo)
350{
351 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
352 struct sigmatel_spec *spec = codec->spec;
353 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
354}
355
356static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
357 struct snd_ctl_elem_value *ucontrol)
358{
359 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
360 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100361 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200362
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100363 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200364 return 0;
365}
366
367static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
368 struct snd_ctl_elem_value *ucontrol)
369{
370 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
371 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100372 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200373
374 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100375 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200376}
377
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100378static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200379{
380 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
381 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200382 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200383}
384
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100385static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200386{
387 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
388 struct sigmatel_spec *spec = codec->spec;
389 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
390
391 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
392 return 0;
393}
394
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100395static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200396{
397 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
398 struct sigmatel_spec *spec = codec->spec;
399 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
400
Mattc7d4b2f2005-06-27 14:59:41 +0200401 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200402 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
403}
404
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200405#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
406
407static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
408 struct snd_ctl_elem_value *ucontrol)
409{
410 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100411 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200412 struct sigmatel_spec *spec = codec->spec;
413
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100414 ucontrol->value.integer.value[0] = !!(spec->aloopback &
415 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200416 return 0;
417}
418
419static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
420 struct snd_ctl_elem_value *ucontrol)
421{
422 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
423 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100424 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200425 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100426 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200427
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100428 idx_val = spec->aloopback_mask << idx;
429 if (ucontrol->value.integer.value[0])
430 val = spec->aloopback | idx_val;
431 else
432 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100433 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200434 return 0;
435
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100436 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200437
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100438 /* Only return the bits defined by the shift value of the
439 * first two bytes of the mask
440 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200441 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100442 kcontrol->private_value & 0xFFFF, 0x0);
443 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200444
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100445 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200446 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100447 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200448 } else {
449 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100450 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200451 }
452
453 snd_hda_codec_write_cache(codec, codec->afg, 0,
454 kcontrol->private_value >> 16, dac_mode);
455
456 return 1;
457}
458
Mattc7d4b2f2005-06-27 14:59:41 +0200459static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200460 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200461 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200462 {}
463};
464
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200465static struct hda_verb stac9200_eapd_init[] = {
466 /* set dac0mux for dac converter */
467 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
468 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
469 {}
470};
471
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100472static struct hda_verb stac92hd73xx_6ch_core_init[] = {
473 /* set master volume and direct control */
474 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
475 /* setup audio connections */
476 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
477 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
478 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
479 /* setup adcs to point to mixer */
480 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
481 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100482 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
483 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
484 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
485 /* setup import muxs */
486 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
487 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
488 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
489 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
490 {}
491};
492
493static struct hda_verb stac92hd73xx_8ch_core_init[] = {
494 /* set master volume and direct control */
495 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
496 /* setup audio connections */
497 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
498 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
499 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
500 /* connect hp ports to dac3 */
501 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
502 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
503 /* setup adcs to point to mixer */
504 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
505 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100506 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
507 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
508 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
509 /* setup import muxs */
510 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
511 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
512 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
513 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
514 {}
515};
516
517static struct hda_verb stac92hd73xx_10ch_core_init[] = {
518 /* set master volume and direct control */
519 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
520 /* setup audio connections */
521 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
522 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
523 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
524 /* dac3 is connected to import3 mux */
525 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
526 /* connect hp ports to dac4 */
527 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
528 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
529 /* setup adcs to point to mixer */
530 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
531 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100532 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
533 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
534 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
535 /* setup import muxs */
536 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
537 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
538 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
539 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
540 {}
541};
542
Matthew Ranostaye035b842007-11-06 11:53:55 +0100543static struct hda_verb stac92hd71bxx_core_init[] = {
544 /* set master volume and direct control */
545 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
546 /* connect headphone jack to dac1 */
547 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100548 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
549 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
550 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
551 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
552 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100553};
554
555static struct hda_verb stac92hd71bxx_analog_core_init[] = {
556 /* set master volume and direct control */
557 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
558 /* connect headphone jack to dac1 */
559 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100560 /* connect ports 0d and 0f to audio mixer */
561 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
562 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100563 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100564 /* unmute dac0 input in audio mixer */
565 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100566 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
567 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
568 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
569 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100570 {}
571};
572
Tobin Davis8e21c342007-01-08 11:04:17 +0100573static struct hda_verb stac925x_core_init[] = {
574 /* set dac0mux for dac converter */
575 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
576 {}
577};
578
Mattc7d4b2f2005-06-27 14:59:41 +0200579static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200580 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200581 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200582 {}
583};
584
Tobin Davis93ed1502006-09-01 21:03:12 +0200585static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200586 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200587 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200588 /* unmute node 0x1b */
589 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
590 /* select node 0x03 as DAC */
591 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
592 {}
593};
594
Matt Porter3cc08dc2006-01-23 15:27:49 +0100595static struct hda_verb stac927x_core_init[] = {
596 /* set master volume and direct control */
597 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
598 {}
599};
600
Matt Porterf3302a52006-07-31 12:49:34 +0200601static struct hda_verb stac9205_core_init[] = {
602 /* set master volume and direct control */
603 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
604 {}
605};
606
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200607#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200608 { \
609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
610 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200611 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200612 .info = stac92xx_mux_enum_info, \
613 .get = stac92xx_mux_enum_get, \
614 .put = stac92xx_mux_enum_put, \
615 }
616
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100617#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200618 { \
619 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
620 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100621 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200622 .info = stac92xx_aloopback_info, \
623 .get = stac92xx_aloopback_get, \
624 .put = stac92xx_aloopback_put, \
625 .private_value = verb_read | (verb_write << 16), \
626 }
627
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100628static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200629 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
630 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200631 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200632 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
633 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200634 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200635 { } /* end */
636};
637
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100638static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100639 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
640
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100641 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
642 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
643
644 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
645 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
646
647 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
648 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
649
650 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
651 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
652
653 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
654 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
655
656 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
657 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
658
659 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
660 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
661 { } /* end */
662};
663
664static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100665 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
666
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100667 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
668 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
669
670 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
671 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
672
673 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
674 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
675
676 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
677 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
678
679 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
680 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
681
682 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
683 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
684
685 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
686 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
687 { } /* end */
688};
689
690static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100691 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
692
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100693 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
694 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
695
696 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
697 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
698
699 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
700 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
701
702 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
703 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
704
705 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
706 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
707
708 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
709 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
710
711 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
712 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
713 { } /* end */
714};
715
Matthew Ranostay541eee82007-12-14 12:08:04 +0100716static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100717 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100718
Matthew Ranostay9b359472007-11-07 13:03:12 +0100719 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
720 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
721 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
722
723 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
724 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
725 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
726
727 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
728 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaya780c0a2008-01-09 12:30:20 +0100729
730 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x14, 0x1, 0, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100731 { } /* end */
732};
733
Matthew Ranostay541eee82007-12-14 12:08:04 +0100734static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100735 STAC_INPUT_SOURCE(2),
736 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
737
Matthew Ranostay541eee82007-12-14 12:08:04 +0100738 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
739 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
740 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
741
742 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
743 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
744 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
Matthew Ranostaya780c0a2008-01-09 12:30:20 +0100745
746 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x14, 0x1, 0, HDA_INPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +0100747 { } /* end */
748};
749
Tobin Davis8e21c342007-01-08 11:04:17 +0100750static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200751 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100752 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
753 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
754 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
755 { } /* end */
756};
757
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100758static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200759 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100760 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200761
762 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
763 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
764 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
765
766 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
767 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
768 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
769
770 { } /* end */
771};
772
773/* This needs to be generated dynamically based on sequence */
774static struct snd_kcontrol_new stac922x_mixer[] = {
775 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200776 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
777 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
778 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
779
780 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
781 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
782 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
783 { } /* end */
784};
785
786
787static struct snd_kcontrol_new stac927x_mixer[] = {
788 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100789 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200790
791 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
792 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
793 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
794
795 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
796 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
797 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
798
799 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
800 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
801 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200802 { } /* end */
803};
804
Takashi Iwai1697055e2007-12-18 18:05:52 +0100805static struct snd_kcontrol_new stac_dmux_mixer = {
806 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
807 .name = "Digital Input Source",
808 /* count set later */
809 .info = stac92xx_dmux_enum_info,
810 .get = stac92xx_dmux_enum_get,
811 .put = stac92xx_dmux_enum_put,
812};
813
Takashi Iwai2134ea42008-01-10 16:53:55 +0100814static const char *slave_vols[] = {
815 "Front Playback Volume",
816 "Surround Playback Volume",
817 "Center Playback Volume",
818 "LFE Playback Volume",
819 "Side Playback Volume",
820 "Headphone Playback Volume",
821 "Headphone Playback Volume",
822 "Speaker Playback Volume",
823 "External Speaker Playback Volume",
824 "Speaker2 Playback Volume",
825 NULL
826};
827
828static const char *slave_sws[] = {
829 "Front Playback Switch",
830 "Surround Playback Switch",
831 "Center Playback Switch",
832 "LFE Playback Switch",
833 "Side Playback Switch",
834 "Headphone Playback Switch",
835 "Headphone Playback Switch",
836 "Speaker Playback Switch",
837 "External Speaker Playback Switch",
838 "Speaker2 Playback Switch",
839 NULL
840};
841
Matt2f2f4252005-04-13 14:45:30 +0200842static int stac92xx_build_controls(struct hda_codec *codec)
843{
844 struct sigmatel_spec *spec = codec->spec;
845 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200846 int i;
Matt2f2f4252005-04-13 14:45:30 +0200847
848 err = snd_hda_add_new_ctls(codec, spec->mixer);
849 if (err < 0)
850 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200851
852 for (i = 0; i < spec->num_mixers; i++) {
853 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
854 if (err < 0)
855 return err;
856 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100857 if (spec->num_dmuxes > 0) {
858 stac_dmux_mixer.count = spec->num_dmuxes;
859 err = snd_ctl_add(codec->bus->card,
860 snd_ctl_new1(&stac_dmux_mixer, codec));
861 if (err < 0)
862 return err;
863 }
Mattc7d4b2f2005-06-27 14:59:41 +0200864
Mattdabbed62005-06-14 10:19:34 +0200865 if (spec->multiout.dig_out_nid) {
866 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
867 if (err < 0)
868 return err;
869 }
870 if (spec->dig_in_nid) {
871 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
872 if (err < 0)
873 return err;
874 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100875
876 /* if we have no master control, let's create it */
877 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
878 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
879 HDA_OUTPUT, spec->vmaster_tlv);
880 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
881 spec->vmaster_tlv, slave_vols);
882 if (err < 0)
883 return err;
884 }
885 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
886 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
887 NULL, slave_sws);
888 if (err < 0)
889 return err;
890 }
891
Mattdabbed62005-06-14 10:19:34 +0200892 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200893}
894
Matt Porter403d1942005-11-29 15:00:51 +0100895static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200896 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200897 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
898};
899
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200900/*
901 STAC 9200 pin configs for
902 102801A8
903 102801DE
904 102801E8
905*/
906static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200907 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
908 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200909};
910
911/*
912 STAC 9200 pin configs for
913 102801C0
914 102801C1
915*/
916static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200917 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
918 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200919};
920
921/*
922 STAC 9200 pin configs for
923 102801C4 (Dell Dimension E310)
924 102801C5
925 102801C7
926 102801D9
927 102801DA
928 102801E3
929*/
930static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200931 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
932 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200933};
934
935
936/*
937 STAC 9200-32 pin configs for
938 102801B5 (Dell Inspiron 630m)
939 102801D8 (Dell Inspiron 640m)
940*/
941static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200942 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
943 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200944};
945
946/*
947 STAC 9200-32 pin configs for
948 102801C2 (Dell Latitude D620)
949 102801C8
950 102801CC (Dell Latitude D820)
951 102801D4
952 102801D6
953*/
954static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200955 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
956 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200957};
958
959/*
960 STAC 9200-32 pin configs for
961 102801CE (Dell XPS M1710)
962 102801CF (Dell Precision M90)
963*/
964static unsigned int dell9200_m23_pin_configs[8] = {
965 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
966 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
967};
968
969/*
970 STAC 9200-32 pin configs for
971 102801C9
972 102801CA
973 102801CB (Dell Latitude 120L)
974 102801D3
975*/
976static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200977 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
978 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200979};
980
981/*
982 STAC 9200-32 pin configs for
983 102801BD (Dell Inspiron E1505n)
984 102801EE
985 102801EF
986*/
987static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200988 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
989 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200990};
991
992/*
993 STAC 9200-32 pin configs for
994 102801F5 (Dell Inspiron 1501)
995 102801F6
996*/
997static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200998 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
999 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001000};
1001
1002/*
1003 STAC 9200-32
1004 102801CD (Dell Inspiron E1705/9400)
1005*/
1006static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001007 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1008 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001009};
1010
1011
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001012static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1013 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001014 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1015 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1016 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1017 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1018 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1019 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1020 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1021 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1022 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1023 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001024};
1025
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001026static const char *stac9200_models[STAC_9200_MODELS] = {
1027 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001028 [STAC_9200_DELL_D21] = "dell-d21",
1029 [STAC_9200_DELL_D22] = "dell-d22",
1030 [STAC_9200_DELL_D23] = "dell-d23",
1031 [STAC_9200_DELL_M21] = "dell-m21",
1032 [STAC_9200_DELL_M22] = "dell-m22",
1033 [STAC_9200_DELL_M23] = "dell-m23",
1034 [STAC_9200_DELL_M24] = "dell-m24",
1035 [STAC_9200_DELL_M25] = "dell-m25",
1036 [STAC_9200_DELL_M26] = "dell-m26",
1037 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001038 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001039};
1040
1041static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1042 /* SigmaTel reference board */
1043 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1044 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001045 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001046 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1047 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001048 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001049 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1050 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1051 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1052 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1053 "unknown Dell", STAC_9200_DELL_D22),
1054 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1055 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001056 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001057 "Dell Latitude D620", STAC_9200_DELL_M22),
1058 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1059 "unknown Dell", STAC_9200_DELL_D23),
1060 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1061 "unknown Dell", STAC_9200_DELL_D23),
1062 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1063 "unknown Dell", STAC_9200_DELL_M22),
1064 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1065 "unknown Dell", STAC_9200_DELL_M24),
1066 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1067 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001068 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001069 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001070 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001071 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001072 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001073 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001074 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001075 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001076 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001077 "Dell Precision M90", STAC_9200_DELL_M23),
1078 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1079 "unknown Dell", STAC_9200_DELL_M22),
1080 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1081 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001082 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001083 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001084 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001085 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1086 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1087 "unknown Dell", STAC_9200_DELL_D23),
1088 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1089 "unknown Dell", STAC_9200_DELL_D23),
1090 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1091 "unknown Dell", STAC_9200_DELL_D21),
1092 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1093 "unknown Dell", STAC_9200_DELL_D23),
1094 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1095 "unknown Dell", STAC_9200_DELL_D21),
1096 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1097 "unknown Dell", STAC_9200_DELL_M25),
1098 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1099 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001100 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001101 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1102 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1103 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001104 /* Panasonic */
1105 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001106 /* Gateway machines needs EAPD to be set on resume */
1107 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1108 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1109 STAC_9200_GATEWAY),
1110 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1111 STAC_9200_GATEWAY),
Matt Porter403d1942005-11-29 15:00:51 +01001112 {} /* terminator */
1113};
1114
Tobin Davis8e21c342007-01-08 11:04:17 +01001115static unsigned int ref925x_pin_configs[8] = {
1116 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1117 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
1118};
1119
1120static unsigned int stac925x_MA6_pin_configs[8] = {
1121 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1122 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1123};
1124
Tobin Davis2c11f952007-05-17 09:36:34 +02001125static unsigned int stac925x_PA6_pin_configs[8] = {
1126 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1127 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1128};
1129
Tobin Davis8e21c342007-01-08 11:04:17 +01001130static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001131 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1132 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001133};
1134
1135static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1136 [STAC_REF] = ref925x_pin_configs,
1137 [STAC_M2_2] = stac925xM2_2_pin_configs,
1138 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001139 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001140};
1141
1142static const char *stac925x_models[STAC_925x_MODELS] = {
1143 [STAC_REF] = "ref",
1144 [STAC_M2_2] = "m2-2",
1145 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001146 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001147};
1148
1149static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1150 /* SigmaTel reference board */
1151 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001152 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001153 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1154 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1155 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001156 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001157 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1158 {} /* terminator */
1159};
1160
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001161static unsigned int ref92hd73xx_pin_configs[12] = {
1162 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1163 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1164 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1165};
1166
1167static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1168 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1169};
1170
1171static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1172 [STAC_92HD73XX_REF] = "ref",
1173};
1174
1175static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1176 /* SigmaTel reference board */
1177 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1178 "DFI LanParty", STAC_92HD73XX_REF),
1179 {} /* terminator */
1180};
1181
Matthew Ranostaye035b842007-11-06 11:53:55 +01001182static unsigned int ref92hd71bxx_pin_configs[10] = {
1183 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
1184 0x0181302e, 0x01114010, 0x01a19020, 0x90a000f0,
1185 0x90a000f0, 0x01452050,
1186};
1187
1188static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1189 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1190};
1191
1192static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1193 [STAC_92HD71BXX_REF] = "ref",
1194};
1195
1196static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1197 /* SigmaTel reference board */
1198 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1199 "DFI LanParty", STAC_92HD71BXX_REF),
1200 {} /* terminator */
1201};
1202
Matt Porter403d1942005-11-29 15:00:51 +01001203static unsigned int ref922x_pin_configs[10] = {
1204 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1205 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001206 0x40000100, 0x40000100,
1207};
1208
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001209/*
1210 STAC 922X pin configs for
1211 102801A7
1212 102801AB
1213 102801A9
1214 102801D1
1215 102801D2
1216*/
1217static unsigned int dell_922x_d81_pin_configs[10] = {
1218 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1219 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1220 0x01813122, 0x400001f2,
1221};
1222
1223/*
1224 STAC 922X pin configs for
1225 102801AC
1226 102801D0
1227*/
1228static unsigned int dell_922x_d82_pin_configs[10] = {
1229 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1230 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1231 0x01813122, 0x400001f1,
1232};
1233
1234/*
1235 STAC 922X pin configs for
1236 102801BF
1237*/
1238static unsigned int dell_922x_m81_pin_configs[10] = {
1239 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1240 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1241 0x40C003f1, 0x405003f0,
1242};
1243
1244/*
1245 STAC 9221 A1 pin configs for
1246 102801D7 (Dell XPS M1210)
1247*/
1248static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001249 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1250 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001251 0x508003f3, 0x405003f4,
1252};
1253
Matt Porter403d1942005-11-29 15:00:51 +01001254static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001255 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001256 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1257 0x02a19120, 0x40000100,
1258};
1259
1260static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001261 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1262 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001263 0x02a19320, 0x40000100,
1264};
1265
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001266static unsigned int intel_mac_v1_pin_configs[10] = {
1267 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1268 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001269 0x400000fc, 0x400000fb,
1270};
1271
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001272static unsigned int intel_mac_v2_pin_configs[10] = {
1273 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1274 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001275 0x400000fc, 0x400000fb,
1276};
1277
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001278static unsigned int intel_mac_v3_pin_configs[10] = {
1279 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1280 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1281 0x400000fc, 0x400000fb,
1282};
1283
1284static unsigned int intel_mac_v4_pin_configs[10] = {
1285 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1286 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1287 0x400000fc, 0x400000fb,
1288};
1289
1290static unsigned int intel_mac_v5_pin_configs[10] = {
1291 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1292 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1293 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001294};
1295
Takashi Iwai76c08822007-06-19 12:17:42 +02001296
Takashi Iwai19039bd2006-06-28 15:52:16 +02001297static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001298 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001299 [STAC_D945GTP3] = d945gtp3_pin_configs,
1300 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001301 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1302 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1303 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1304 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1305 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001306 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001307 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1308 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1309 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1310 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1311 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1312 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001313 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1314 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1315 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1316 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001317};
1318
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001319static const char *stac922x_models[STAC_922X_MODELS] = {
1320 [STAC_D945_REF] = "ref",
1321 [STAC_D945GTP5] = "5stack",
1322 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001323 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1324 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1325 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1326 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1327 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001328 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001329 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001330 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001331 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1332 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001333 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001334 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001335 [STAC_922X_DELL_D81] = "dell-d81",
1336 [STAC_922X_DELL_D82] = "dell-d82",
1337 [STAC_922X_DELL_M81] = "dell-m81",
1338 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001339};
1340
1341static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1342 /* SigmaTel reference board */
1343 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1344 "DFI LanParty", STAC_D945_REF),
1345 /* Intel 945G based systems */
1346 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1347 "Intel D945G", STAC_D945GTP3),
1348 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1349 "Intel D945G", STAC_D945GTP3),
1350 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1351 "Intel D945G", STAC_D945GTP3),
1352 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1353 "Intel D945G", STAC_D945GTP3),
1354 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1355 "Intel D945G", STAC_D945GTP3),
1356 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1357 "Intel D945G", STAC_D945GTP3),
1358 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1359 "Intel D945G", STAC_D945GTP3),
1360 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1361 "Intel D945G", STAC_D945GTP3),
1362 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1363 "Intel D945G", STAC_D945GTP3),
1364 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1365 "Intel D945G", STAC_D945GTP3),
1366 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1367 "Intel D945G", STAC_D945GTP3),
1368 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1369 "Intel D945G", STAC_D945GTP3),
1370 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1371 "Intel D945G", STAC_D945GTP3),
1372 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1373 "Intel D945G", STAC_D945GTP3),
1374 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1375 "Intel D945G", STAC_D945GTP3),
1376 /* Intel D945G 5-stack systems */
1377 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1378 "Intel D945G", STAC_D945GTP5),
1379 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1380 "Intel D945G", STAC_D945GTP5),
1381 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1382 "Intel D945G", STAC_D945GTP5),
1383 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1384 "Intel D945G", STAC_D945GTP5),
1385 /* Intel 945P based systems */
1386 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1387 "Intel D945P", STAC_D945GTP3),
1388 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1389 "Intel D945P", STAC_D945GTP3),
1390 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1391 "Intel D945P", STAC_D945GTP3),
1392 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1393 "Intel D945P", STAC_D945GTP3),
1394 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1395 "Intel D945P", STAC_D945GTP3),
1396 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1397 "Intel D945P", STAC_D945GTP5),
1398 /* other systems */
1399 /* Apple Mac Mini (early 2006) */
1400 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001401 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001402 /* Dell systems */
1403 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1404 "unknown Dell", STAC_922X_DELL_D81),
1405 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1406 "unknown Dell", STAC_922X_DELL_D81),
1407 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1408 "unknown Dell", STAC_922X_DELL_D81),
1409 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1410 "unknown Dell", STAC_922X_DELL_D82),
1411 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1412 "unknown Dell", STAC_922X_DELL_M81),
1413 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1414 "unknown Dell", STAC_922X_DELL_D82),
1415 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1416 "unknown Dell", STAC_922X_DELL_D81),
1417 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1418 "unknown Dell", STAC_922X_DELL_D81),
1419 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1420 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001421 {} /* terminator */
1422};
1423
Matt Porter3cc08dc2006-01-23 15:27:49 +01001424static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001425 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1426 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1427 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1428 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001429};
1430
Tobin Davis93ed1502006-09-01 21:03:12 +02001431static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001432 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1433 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1434 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1435 0x40000100, 0x40000100
1436};
1437
Tobin Davis93ed1502006-09-01 21:03:12 +02001438static unsigned int d965_5st_pin_configs[14] = {
1439 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1440 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1441 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1442 0x40000100, 0x40000100
1443};
1444
Tobin Davis4ff076e2007-08-07 11:48:12 +02001445static unsigned int dell_3st_pin_configs[14] = {
1446 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1447 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001448 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001449 0x40c003fc, 0x40000100
1450};
1451
Tobin Davis93ed1502006-09-01 21:03:12 +02001452static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001453 [STAC_D965_REF] = ref927x_pin_configs,
1454 [STAC_D965_3ST] = d965_3st_pin_configs,
1455 [STAC_D965_5ST] = d965_5st_pin_configs,
1456 [STAC_DELL_3ST] = dell_3st_pin_configs,
1457 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001458};
1459
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001460static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001461 [STAC_D965_REF] = "ref",
1462 [STAC_D965_3ST] = "3stack",
1463 [STAC_D965_5ST] = "5stack",
1464 [STAC_DELL_3ST] = "dell-3stack",
1465 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001466};
1467
1468static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1469 /* SigmaTel reference board */
1470 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1471 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001472 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001473 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1474 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001475 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001476 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1477 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1478 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1479 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1480 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1481 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1482 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1483 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1484 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1485 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1486 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1487 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1488 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1489 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1490 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1491 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001492 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001493 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001494 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001495 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1496 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001497 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001498 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1499 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001500 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1501 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1502 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1503 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1505 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001506 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001507 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1509 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1510 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1511 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1514 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001516 {} /* terminator */
1517};
1518
Matt Porterf3302a52006-07-31 12:49:34 +02001519static unsigned int ref9205_pin_configs[12] = {
1520 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matt Porter8b657272006-10-26 17:12:59 +02001521 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
1522 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001523};
1524
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001525/*
1526 STAC 9205 pin configs for
1527 102801F1
1528 102801F2
1529 102801FC
1530 102801FD
1531 10280204
1532 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001533 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001534*/
1535static unsigned int dell_9205_m42_pin_configs[12] = {
1536 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1537 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1538 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1539};
1540
1541/*
1542 STAC 9205 pin configs for
1543 102801F9
1544 102801FA
1545 102801FE
1546 102801FF (Dell Precision M4300)
1547 10280206
1548 10280200
1549 10280201
1550*/
1551static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001552 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1553 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1554 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1555};
1556
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001557static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001558 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1559 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1560 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1561};
1562
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001563static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001564 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001565 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1566 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1567 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001568};
1569
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001570static const char *stac9205_models[STAC_9205_MODELS] = {
1571 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001572 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001573 [STAC_9205_DELL_M43] = "dell-m43",
1574 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001575};
1576
1577static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1578 /* SigmaTel reference board */
1579 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1580 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001581 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1582 "unknown Dell", STAC_9205_DELL_M42),
1583 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1584 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001585 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001586 "Dell Precision", STAC_9205_DELL_M43),
1587 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1588 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001589 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1590 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001591 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1592 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001593 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1594 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001595 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1596 "unknown Dell", STAC_9205_DELL_M42),
1597 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1598 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001599 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1600 "Dell Precision", STAC_9205_DELL_M43),
1601 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001602 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001603 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1604 "Dell Precision", STAC_9205_DELL_M43),
1605 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1606 "Dell Inspiron", STAC_9205_DELL_M44),
1607 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1608 "Dell Inspiron", STAC_9205_DELL_M44),
1609 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1610 "Dell Inspiron", STAC_9205_DELL_M44),
1611 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1612 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001613 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1614 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001615 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1616 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001617 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1618 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001619 {} /* terminator */
1620};
1621
Richard Fish11b44bb2006-08-23 18:31:34 +02001622static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1623{
1624 int i;
1625 struct sigmatel_spec *spec = codec->spec;
1626
1627 if (! spec->bios_pin_configs) {
1628 spec->bios_pin_configs = kcalloc(spec->num_pins,
1629 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1630 if (! spec->bios_pin_configs)
1631 return -ENOMEM;
1632 }
1633
1634 for (i = 0; i < spec->num_pins; i++) {
1635 hda_nid_t nid = spec->pin_nids[i];
1636 unsigned int pin_cfg;
1637
1638 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1639 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1640 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1641 nid, pin_cfg);
1642 spec->bios_pin_configs[i] = pin_cfg;
1643 }
1644
1645 return 0;
1646}
1647
Matthew Ranostay87d48362007-07-17 11:52:24 +02001648static void stac92xx_set_config_reg(struct hda_codec *codec,
1649 hda_nid_t pin_nid, unsigned int pin_config)
1650{
1651 int i;
1652 snd_hda_codec_write(codec, pin_nid, 0,
1653 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1654 pin_config & 0x000000ff);
1655 snd_hda_codec_write(codec, pin_nid, 0,
1656 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1657 (pin_config & 0x0000ff00) >> 8);
1658 snd_hda_codec_write(codec, pin_nid, 0,
1659 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1660 (pin_config & 0x00ff0000) >> 16);
1661 snd_hda_codec_write(codec, pin_nid, 0,
1662 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1663 pin_config >> 24);
1664 i = snd_hda_codec_read(codec, pin_nid, 0,
1665 AC_VERB_GET_CONFIG_DEFAULT,
1666 0x00);
1667 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1668 pin_nid, i);
1669}
1670
Matt2f2f4252005-04-13 14:45:30 +02001671static void stac92xx_set_config_regs(struct hda_codec *codec)
1672{
1673 int i;
1674 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001675
Matthew Ranostay87d48362007-07-17 11:52:24 +02001676 if (!spec->pin_configs)
1677 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001678
Matthew Ranostay87d48362007-07-17 11:52:24 +02001679 for (i = 0; i < spec->num_pins; i++)
1680 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1681 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001682}
Matt2f2f4252005-04-13 14:45:30 +02001683
Takashi Iwai82599802007-07-31 15:56:24 +02001684static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
Matthew Ranostay92a22be2007-06-19 16:48:28 +02001685{
Takashi Iwai82599802007-07-31 15:56:24 +02001686 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay87d48362007-07-17 11:52:24 +02001687 /* Configure GPIOx as output */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001688 snd_hda_codec_write_cache(codec, codec->afg, 0,
1689 AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001690 /* Configure GPIOx as CMOS */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001691 snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001692 /* Assert GPIOx */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001693 snd_hda_codec_write_cache(codec, codec->afg, 0,
1694 AC_VERB_SET_GPIO_DATA, spec->gpio_data);
Matthew Ranostay87d48362007-07-17 11:52:24 +02001695 /* Enable GPIOx */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001696 snd_hda_codec_write_cache(codec, codec->afg, 0,
1697 AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
Matthew Ranostay92a22be2007-06-19 16:48:28 +02001698}
1699
Matt2f2f4252005-04-13 14:45:30 +02001700/*
1701 * Analog playback callbacks
1702 */
1703static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1704 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001705 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001706{
1707 struct sigmatel_spec *spec = codec->spec;
1708 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1709}
1710
1711static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1712 struct hda_codec *codec,
1713 unsigned int stream_tag,
1714 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001715 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001716{
1717 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001718 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001719}
1720
1721static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1722 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001723 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001724{
1725 struct sigmatel_spec *spec = codec->spec;
1726 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1727}
1728
1729/*
Mattdabbed62005-06-14 10:19:34 +02001730 * Digital playback callbacks
1731 */
1732static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1733 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001734 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001735{
1736 struct sigmatel_spec *spec = codec->spec;
1737 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1738}
1739
1740static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1741 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001742 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001743{
1744 struct sigmatel_spec *spec = codec->spec;
1745 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1746}
1747
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001748static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1749 struct hda_codec *codec,
1750 unsigned int stream_tag,
1751 unsigned int format,
1752 struct snd_pcm_substream *substream)
1753{
1754 struct sigmatel_spec *spec = codec->spec;
1755 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1756 stream_tag, format, substream);
1757}
1758
Mattdabbed62005-06-14 10:19:34 +02001759
1760/*
Matt2f2f4252005-04-13 14:45:30 +02001761 * Analog capture callbacks
1762 */
1763static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1764 struct hda_codec *codec,
1765 unsigned int stream_tag,
1766 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001767 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001768{
1769 struct sigmatel_spec *spec = codec->spec;
1770
1771 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1772 stream_tag, 0, format);
1773 return 0;
1774}
1775
1776static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1777 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001778 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001779{
1780 struct sigmatel_spec *spec = codec->spec;
1781
1782 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1783 return 0;
1784}
1785
Mattdabbed62005-06-14 10:19:34 +02001786static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1787 .substreams = 1,
1788 .channels_min = 2,
1789 .channels_max = 2,
1790 /* NID is set in stac92xx_build_pcms */
1791 .ops = {
1792 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001793 .close = stac92xx_dig_playback_pcm_close,
1794 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001795 },
1796};
1797
1798static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1799 .substreams = 1,
1800 .channels_min = 2,
1801 .channels_max = 2,
1802 /* NID is set in stac92xx_build_pcms */
1803};
1804
Matt2f2f4252005-04-13 14:45:30 +02001805static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1806 .substreams = 1,
1807 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001808 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001809 .nid = 0x02, /* NID to query formats and rates */
1810 .ops = {
1811 .open = stac92xx_playback_pcm_open,
1812 .prepare = stac92xx_playback_pcm_prepare,
1813 .cleanup = stac92xx_playback_pcm_cleanup
1814 },
1815};
1816
Matt Porter3cc08dc2006-01-23 15:27:49 +01001817static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1818 .substreams = 1,
1819 .channels_min = 2,
1820 .channels_max = 2,
1821 .nid = 0x06, /* NID to query formats and rates */
1822 .ops = {
1823 .open = stac92xx_playback_pcm_open,
1824 .prepare = stac92xx_playback_pcm_prepare,
1825 .cleanup = stac92xx_playback_pcm_cleanup
1826 },
1827};
1828
Matt2f2f4252005-04-13 14:45:30 +02001829static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001830 .channels_min = 2,
1831 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001832 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001833 .ops = {
1834 .prepare = stac92xx_capture_pcm_prepare,
1835 .cleanup = stac92xx_capture_pcm_cleanup
1836 },
1837};
1838
1839static int stac92xx_build_pcms(struct hda_codec *codec)
1840{
1841 struct sigmatel_spec *spec = codec->spec;
1842 struct hda_pcm *info = spec->pcm_rec;
1843
1844 codec->num_pcms = 1;
1845 codec->pcm_info = info;
1846
Mattc7d4b2f2005-06-27 14:59:41 +02001847 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001848 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001849 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001850 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001851 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001852
1853 if (spec->alt_switch) {
1854 codec->num_pcms++;
1855 info++;
1856 info->name = "STAC92xx Analog Alt";
1857 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1858 }
Matt2f2f4252005-04-13 14:45:30 +02001859
Mattdabbed62005-06-14 10:19:34 +02001860 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1861 codec->num_pcms++;
1862 info++;
1863 info->name = "STAC92xx Digital";
1864 if (spec->multiout.dig_out_nid) {
1865 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1866 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1867 }
1868 if (spec->dig_in_nid) {
1869 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1870 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1871 }
1872 }
1873
Matt2f2f4252005-04-13 14:45:30 +02001874 return 0;
1875}
1876
Takashi Iwaic960a032006-03-23 17:06:28 +01001877static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1878{
1879 unsigned int pincap = snd_hda_param_read(codec, nid,
1880 AC_PAR_PIN_CAP);
1881 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1882 if (pincap & AC_PINCAP_VREF_100)
1883 return AC_PINCTL_VREF_100;
1884 if (pincap & AC_PINCAP_VREF_80)
1885 return AC_PINCTL_VREF_80;
1886 if (pincap & AC_PINCAP_VREF_50)
1887 return AC_PINCTL_VREF_50;
1888 if (pincap & AC_PINCAP_VREF_GRD)
1889 return AC_PINCTL_VREF_GRD;
1890 return 0;
1891}
1892
Matt Porter403d1942005-11-29 15:00:51 +01001893static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1894
1895{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001896 snd_hda_codec_write_cache(codec, nid, 0,
1897 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001898}
1899
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001900#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001901
1902static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1903{
1904 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1905 struct sigmatel_spec *spec = codec->spec;
1906 int io_idx = kcontrol-> private_value & 0xff;
1907
1908 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1909 return 0;
1910}
1911
1912static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1913{
1914 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1915 struct sigmatel_spec *spec = codec->spec;
1916 hda_nid_t nid = kcontrol->private_value >> 8;
1917 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001918 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001919
1920 spec->io_switch[io_idx] = val;
1921
1922 if (val)
1923 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001924 else {
1925 unsigned int pinctl = AC_PINCTL_IN_EN;
1926 if (io_idx) /* set VREF for mic */
1927 pinctl |= stac92xx_get_vref(codec, nid);
1928 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1929 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001930
1931 /* check the auto-mute again: we need to mute/unmute the speaker
1932 * appropriately according to the pin direction
1933 */
1934 if (spec->hp_detect)
1935 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1936
Matt Porter403d1942005-11-29 15:00:51 +01001937 return 1;
1938}
1939
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001940#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1941
1942static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1943 struct snd_ctl_elem_value *ucontrol)
1944{
1945 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1946 struct sigmatel_spec *spec = codec->spec;
1947
1948 ucontrol->value.integer.value[0] = spec->clfe_swap;
1949 return 0;
1950}
1951
1952static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1953 struct snd_ctl_elem_value *ucontrol)
1954{
1955 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1956 struct sigmatel_spec *spec = codec->spec;
1957 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001958 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001959
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001960 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001961 return 0;
1962
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001963 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001964
1965 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1966 spec->clfe_swap ? 0x4 : 0x0);
1967
1968 return 1;
1969}
1970
Matt Porter403d1942005-11-29 15:00:51 +01001971#define STAC_CODEC_IO_SWITCH(xname, xpval) \
1972 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1973 .name = xname, \
1974 .index = 0, \
1975 .info = stac92xx_io_switch_info, \
1976 .get = stac92xx_io_switch_get, \
1977 .put = stac92xx_io_switch_put, \
1978 .private_value = xpval, \
1979 }
1980
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001981#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
1982 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1983 .name = xname, \
1984 .index = 0, \
1985 .info = stac92xx_clfe_switch_info, \
1986 .get = stac92xx_clfe_switch_get, \
1987 .put = stac92xx_clfe_switch_put, \
1988 .private_value = xpval, \
1989 }
Matt Porter403d1942005-11-29 15:00:51 +01001990
Mattc7d4b2f2005-06-27 14:59:41 +02001991enum {
1992 STAC_CTL_WIDGET_VOL,
1993 STAC_CTL_WIDGET_MUTE,
Matt Porter403d1942005-11-29 15:00:51 +01001994 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001995 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02001996};
1997
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001998static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02001999 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2000 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matt Porter403d1942005-11-29 15:00:51 +01002001 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002002 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002003};
2004
2005/* add dynamic controls */
2006static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2007{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002008 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002009
2010 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2011 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2012
2013 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2014 if (! knew)
2015 return -ENOMEM;
2016 if (spec->kctl_alloc) {
2017 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2018 kfree(spec->kctl_alloc);
2019 }
2020 spec->kctl_alloc = knew;
2021 spec->num_kctl_alloc = num;
2022 }
2023
2024 knew = &spec->kctl_alloc[spec->num_kctl_used];
2025 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002026 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002027 if (! knew->name)
2028 return -ENOMEM;
2029 knew->private_value = val;
2030 spec->num_kctl_used++;
2031 return 0;
2032}
2033
Matt Porter403d1942005-11-29 15:00:51 +01002034/* flag inputs as additional dynamic lineouts */
2035static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2036{
2037 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002038 unsigned int wcaps, wtype;
2039 int i, num_dacs = 0;
2040
2041 /* use the wcaps cache to count all DACs available for line-outs */
2042 for (i = 0; i < codec->num_nodes; i++) {
2043 wcaps = codec->wcaps[i];
2044 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002045
Steve Longerbeam7b043892007-05-03 20:50:03 +02002046 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2047 num_dacs++;
2048 }
Matt Porter403d1942005-11-29 15:00:51 +01002049
Steve Longerbeam7b043892007-05-03 20:50:03 +02002050 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2051
Matt Porter403d1942005-11-29 15:00:51 +01002052 switch (cfg->line_outs) {
2053 case 3:
2054 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002055 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002056 cfg->line_out_pins[cfg->line_outs] =
2057 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002058 spec->line_switch = 1;
2059 cfg->line_outs++;
2060 }
2061 break;
2062 case 2:
2063 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002064 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002065 cfg->line_out_pins[cfg->line_outs] =
2066 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002067 spec->line_switch = 1;
2068 cfg->line_outs++;
2069 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002070 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002071 cfg->line_out_pins[cfg->line_outs] =
2072 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002073 spec->mic_switch = 1;
2074 cfg->line_outs++;
2075 }
2076 break;
2077 case 1:
2078 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002079 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002080 cfg->line_out_pins[cfg->line_outs] =
2081 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002082 spec->line_switch = 1;
2083 cfg->line_outs++;
2084 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002085 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002086 cfg->line_out_pins[cfg->line_outs] =
2087 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002088 spec->mic_switch = 1;
2089 cfg->line_outs++;
2090 }
2091 break;
2092 }
2093
2094 return 0;
2095}
2096
Steve Longerbeam7b043892007-05-03 20:50:03 +02002097
2098static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2099{
2100 int i;
2101
2102 for (i = 0; i < spec->multiout.num_dacs; i++) {
2103 if (spec->multiout.dac_nids[i] == nid)
2104 return 1;
2105 }
2106
2107 return 0;
2108}
2109
Matt Porter3cc08dc2006-01-23 15:27:49 +01002110/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002111 * Fill in the dac_nids table from the parsed pin configuration
2112 * This function only works when every pin in line_out_pins[]
2113 * contains atleast one DAC in its connection list. Some 92xx
2114 * codecs are not connected directly to a DAC, such as the 9200
2115 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002116 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002117static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002118 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002119{
2120 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002121 int i, j, conn_len = 0;
2122 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2123 unsigned int wcaps, wtype;
2124
Mattc7d4b2f2005-06-27 14:59:41 +02002125 for (i = 0; i < cfg->line_outs; i++) {
2126 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002127 conn_len = snd_hda_get_connections(codec, nid, conn,
2128 HDA_MAX_CONNECTIONS);
2129 for (j = 0; j < conn_len; j++) {
2130 wcaps = snd_hda_param_read(codec, conn[j],
2131 AC_PAR_AUDIO_WIDGET_CAP);
2132 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002133 if (wtype != AC_WID_AUD_OUT ||
2134 (wcaps & AC_WCAP_DIGITAL))
2135 continue;
2136 /* conn[j] is a DAC routed to this line-out */
2137 if (!is_in_dac_nids(spec, conn[j]))
2138 break;
2139 }
2140
2141 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002142 if (spec->multiout.num_dacs > 0) {
2143 /* we have already working output pins,
2144 * so let's drop the broken ones again
2145 */
2146 cfg->line_outs = spec->multiout.num_dacs;
2147 break;
2148 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002149 /* error out, no available DAC found */
2150 snd_printk(KERN_ERR
2151 "%s: No available DAC for pin 0x%x\n",
2152 __func__, nid);
2153 return -ENODEV;
2154 }
2155
2156 spec->multiout.dac_nids[i] = conn[j];
2157 spec->multiout.num_dacs++;
2158 if (conn_len > 1) {
2159 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002160 snd_hda_codec_write_cache(codec, nid, 0,
2161 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002162
2163 }
Mattc7d4b2f2005-06-27 14:59:41 +02002164 }
2165
Steve Longerbeam7b043892007-05-03 20:50:03 +02002166 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2167 spec->multiout.num_dacs,
2168 spec->multiout.dac_nids[0],
2169 spec->multiout.dac_nids[1],
2170 spec->multiout.dac_nids[2],
2171 spec->multiout.dac_nids[3],
2172 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002173 return 0;
2174}
2175
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002176/* create volume control/switch for the given prefx type */
2177static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2178{
2179 char name[32];
2180 int err;
2181
2182 sprintf(name, "%s Playback Volume", pfx);
2183 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2184 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2185 if (err < 0)
2186 return err;
2187 sprintf(name, "%s Playback Switch", pfx);
2188 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2189 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2190 if (err < 0)
2191 return err;
2192 return 0;
2193}
2194
Mattc7d4b2f2005-06-27 14:59:41 +02002195/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002196static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002197 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002198{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002199 static const char *chname[4] = {
2200 "Front", "Surround", NULL /*CLFE*/, "Side"
2201 };
Mattc7d4b2f2005-06-27 14:59:41 +02002202 hda_nid_t nid;
2203 int i, err;
2204
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002205 struct sigmatel_spec *spec = codec->spec;
2206 unsigned int wid_caps;
2207
2208
Mattc7d4b2f2005-06-27 14:59:41 +02002209 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002210 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002211 continue;
2212
2213 nid = spec->multiout.dac_nids[i];
2214
2215 if (i == 2) {
2216 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002217 err = create_controls(spec, "Center", nid, 1);
2218 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002219 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002220 err = create_controls(spec, "LFE", nid, 2);
2221 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002222 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002223
2224 wid_caps = get_wcaps(codec, nid);
2225
2226 if (wid_caps & AC_WCAP_LR_SWAP) {
2227 err = stac92xx_add_control(spec,
2228 STAC_CTL_WIDGET_CLFE_SWITCH,
2229 "Swap Center/LFE Playback Switch", nid);
2230
2231 if (err < 0)
2232 return err;
2233 }
2234
Mattc7d4b2f2005-06-27 14:59:41 +02002235 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002236 err = create_controls(spec, chname[i], nid, 3);
2237 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002238 return err;
2239 }
2240 }
2241
Matt Porter403d1942005-11-29 15:00:51 +01002242 if (spec->line_switch)
2243 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
2244 return err;
2245
2246 if (spec->mic_switch)
2247 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
2248 return err;
2249
Mattc7d4b2f2005-06-27 14:59:41 +02002250 return 0;
2251}
2252
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002253static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2254{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002255 if (is_in_dac_nids(spec, nid))
2256 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002257 if (spec->multiout.hp_nid == nid)
2258 return 1;
2259 return 0;
2260}
2261
2262static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2263{
2264 if (!spec->multiout.hp_nid)
2265 spec->multiout.hp_nid = nid;
2266 else if (spec->multiout.num_dacs > 4) {
2267 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2268 return 1;
2269 } else {
2270 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2271 spec->multiout.num_dacs++;
2272 }
2273 return 0;
2274}
2275
2276/* add playback controls for Speaker and HP outputs */
2277static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2278 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002279{
2280 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002281 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002282 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002283
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002284 old_num_dacs = spec->multiout.num_dacs;
2285 for (i = 0; i < cfg->hp_outs; i++) {
2286 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2287 if (wid_caps & AC_WCAP_UNSOL_CAP)
2288 spec->hp_detect = 1;
2289 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2290 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2291 if (check_in_dac_nids(spec, nid))
2292 nid = 0;
2293 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002294 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002295 add_spec_dacs(spec, nid);
2296 }
2297 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002298 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002299 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2300 if (check_in_dac_nids(spec, nid))
2301 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002302 if (! nid)
2303 continue;
2304 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002305 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002306 for (i = 0; i < cfg->line_outs; i++) {
2307 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2308 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2309 if (check_in_dac_nids(spec, nid))
2310 nid = 0;
2311 if (! nid)
2312 continue;
2313 add_spec_dacs(spec, nid);
2314 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002315 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2316 static const char *pfxs[] = {
2317 "Speaker", "External Speaker", "Speaker2",
2318 };
2319 err = create_controls(spec, pfxs[i - old_num_dacs],
2320 spec->multiout.dac_nids[i], 3);
2321 if (err < 0)
2322 return err;
2323 }
2324 if (spec->multiout.hp_nid) {
2325 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002326 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002327 pfx = "Master";
2328 else
2329 pfx = "Headphone";
2330 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2331 if (err < 0)
2332 return err;
2333 }
Mattc7d4b2f2005-06-27 14:59:41 +02002334
2335 return 0;
2336}
2337
Matt Porter8b657272006-10-26 17:12:59 +02002338/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002339static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002340 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2341 "Digital Mic 3", "Digital Mic 4"
2342};
2343
2344/* create playback/capture controls for input pins on dmic capable codecs */
2345static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2346 const struct auto_pin_cfg *cfg)
2347{
2348 struct sigmatel_spec *spec = codec->spec;
2349 struct hda_input_mux *dimux = &spec->private_dimux;
2350 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002351 int err, i, j;
2352 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002353
2354 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2355 dimux->items[dimux->num_items].index = 0;
2356 dimux->num_items++;
2357
2358 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002359 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002360 int index;
2361 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002362 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002363 unsigned int def_conf;
2364
2365 def_conf = snd_hda_codec_read(codec,
2366 spec->dmic_nids[i],
2367 0,
2368 AC_VERB_GET_CONFIG_DEFAULT,
2369 0);
2370 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2371 continue;
2372
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002373 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002374 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002375 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002376 con_lst,
2377 HDA_MAX_NUM_INPUTS);
2378 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002379 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002380 index = j;
2381 goto found;
2382 }
2383 continue;
2384found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002385 wcaps = get_wcaps(codec, nid);
2386
2387 if (wcaps & AC_WCAP_OUT_AMP) {
2388 sprintf(name, "%s Capture Volume",
2389 stac92xx_dmic_labels[dimux->num_items]);
2390
2391 err = stac92xx_add_control(spec,
2392 STAC_CTL_WIDGET_VOL,
2393 name,
2394 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2395 if (err < 0)
2396 return err;
2397 }
2398
Matt Porter8b657272006-10-26 17:12:59 +02002399 dimux->items[dimux->num_items].label =
2400 stac92xx_dmic_labels[dimux->num_items];
2401 dimux->items[dimux->num_items].index = index;
2402 dimux->num_items++;
2403 }
2404
2405 return 0;
2406}
2407
Mattc7d4b2f2005-06-27 14:59:41 +02002408/* create playback/capture controls for input pins */
2409static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2410{
2411 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002412 struct hda_input_mux *imux = &spec->private_imux;
2413 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2414 int i, j, k;
2415
2416 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002417 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002418
Takashi Iwai314634b2006-09-21 11:56:18 +02002419 if (!cfg->input_pins[i])
2420 continue;
2421 index = -1;
2422 for (j = 0; j < spec->num_muxes; j++) {
2423 int num_cons;
2424 num_cons = snd_hda_get_connections(codec,
2425 spec->mux_nids[j],
2426 con_lst,
2427 HDA_MAX_NUM_INPUTS);
2428 for (k = 0; k < num_cons; k++)
2429 if (con_lst[k] == cfg->input_pins[i]) {
2430 index = k;
2431 goto found;
2432 }
Mattc7d4b2f2005-06-27 14:59:41 +02002433 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002434 continue;
2435 found:
2436 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2437 imux->items[imux->num_items].index = index;
2438 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002439 }
2440
Steve Longerbeam7b043892007-05-03 20:50:03 +02002441 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002442 /*
2443 * Set the current input for the muxes.
2444 * The STAC9221 has two input muxes with identical source
2445 * NID lists. Hopefully this won't get confused.
2446 */
2447 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002448 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2449 AC_VERB_SET_CONNECT_SEL,
2450 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002451 }
2452 }
2453
Mattc7d4b2f2005-06-27 14:59:41 +02002454 return 0;
2455}
2456
Mattc7d4b2f2005-06-27 14:59:41 +02002457static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2458{
2459 struct sigmatel_spec *spec = codec->spec;
2460 int i;
2461
2462 for (i = 0; i < spec->autocfg.line_outs; i++) {
2463 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2464 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2465 }
2466}
2467
2468static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2469{
2470 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002471 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002472
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002473 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2474 hda_nid_t pin;
2475 pin = spec->autocfg.hp_pins[i];
2476 if (pin) /* connect to front */
2477 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2478 }
2479 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2480 hda_nid_t pin;
2481 pin = spec->autocfg.speaker_pins[i];
2482 if (pin) /* connect to front */
2483 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2484 }
Mattc7d4b2f2005-06-27 14:59:41 +02002485}
2486
Matt Porter3cc08dc2006-01-23 15:27:49 +01002487static 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 +02002488{
2489 struct sigmatel_spec *spec = codec->spec;
2490 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002491 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002492
Matt Porter8b657272006-10-26 17:12:59 +02002493 if ((err = snd_hda_parse_pin_def_config(codec,
2494 &spec->autocfg,
2495 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002496 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002497 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002498 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002499
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002500 /* If we have no real line-out pin and multiple hp-outs, HPs should
2501 * be set up as multi-channel outputs.
2502 */
2503 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2504 spec->autocfg.hp_outs > 1) {
2505 /* Copy hp_outs to line_outs, backup line_outs in
2506 * speaker_outs so that the following routines can handle
2507 * HP pins as primary outputs.
2508 */
2509 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2510 sizeof(spec->autocfg.line_out_pins));
2511 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2512 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2513 sizeof(spec->autocfg.hp_pins));
2514 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2515 hp_speaker_swap = 1;
2516 }
2517
Matt Porter403d1942005-11-29 15:00:51 +01002518 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2519 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002520 if (spec->multiout.num_dacs == 0)
2521 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2522 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002523
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002524 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2525
2526 if (err < 0)
2527 return err;
2528
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002529 if (hp_speaker_swap == 1) {
2530 /* Restore the hp_outs and line_outs */
2531 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2532 sizeof(spec->autocfg.line_out_pins));
2533 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2534 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2535 sizeof(spec->autocfg.speaker_pins));
2536 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2537 memset(spec->autocfg.speaker_pins, 0,
2538 sizeof(spec->autocfg.speaker_pins));
2539 spec->autocfg.speaker_outs = 0;
2540 }
2541
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002542 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2543
2544 if (err < 0)
2545 return err;
2546
2547 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2548
2549 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002550 return err;
2551
Matt Porter8b657272006-10-26 17:12:59 +02002552 if (spec->num_dmics > 0)
2553 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2554 &spec->autocfg)) < 0)
2555 return err;
2556
Mattc7d4b2f2005-06-27 14:59:41 +02002557 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002558 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002559 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002560
Takashi Iwai82bc9552006-03-21 11:24:42 +01002561 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002562 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002563 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002564 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002565
2566 if (spec->kctl_alloc)
2567 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2568
2569 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002570 if (!spec->dinput_mux)
2571 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002572
2573 return 1;
2574}
2575
Takashi Iwai82bc9552006-03-21 11:24:42 +01002576/* add playback controls for HP output */
2577static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2578 struct auto_pin_cfg *cfg)
2579{
2580 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002581 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002582 unsigned int wid_caps;
2583
2584 if (! pin)
2585 return 0;
2586
2587 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002588 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002589 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002590
2591 return 0;
2592}
2593
Richard Fish160ea0d2006-09-06 13:58:25 +02002594/* add playback controls for LFE output */
2595static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2596 struct auto_pin_cfg *cfg)
2597{
2598 struct sigmatel_spec *spec = codec->spec;
2599 int err;
2600 hda_nid_t lfe_pin = 0x0;
2601 int i;
2602
2603 /*
2604 * search speaker outs and line outs for a mono speaker pin
2605 * with an amp. If one is found, add LFE controls
2606 * for it.
2607 */
2608 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2609 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2610 unsigned long wcaps = get_wcaps(codec, pin);
2611 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2612 if (wcaps == AC_WCAP_OUT_AMP)
2613 /* found a mono speaker with an amp, must be lfe */
2614 lfe_pin = pin;
2615 }
2616
2617 /* if speaker_outs is 0, then speakers may be in line_outs */
2618 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2619 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2620 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2621 unsigned long cfg;
2622 cfg = snd_hda_codec_read(codec, pin, 0,
2623 AC_VERB_GET_CONFIG_DEFAULT,
2624 0x00);
2625 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2626 unsigned long wcaps = get_wcaps(codec, pin);
2627 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2628 if (wcaps == AC_WCAP_OUT_AMP)
2629 /* found a mono speaker with an amp,
2630 must be lfe */
2631 lfe_pin = pin;
2632 }
2633 }
2634 }
2635
2636 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002637 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002638 if (err < 0)
2639 return err;
2640 }
2641
2642 return 0;
2643}
2644
Mattc7d4b2f2005-06-27 14:59:41 +02002645static int stac9200_parse_auto_config(struct hda_codec *codec)
2646{
2647 struct sigmatel_spec *spec = codec->spec;
2648 int err;
2649
Kailang Yangdf694da2005-12-05 19:42:22 +01002650 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002651 return err;
2652
2653 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2654 return err;
2655
Takashi Iwai82bc9552006-03-21 11:24:42 +01002656 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2657 return err;
2658
Richard Fish160ea0d2006-09-06 13:58:25 +02002659 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2660 return err;
2661
Takashi Iwai82bc9552006-03-21 11:24:42 +01002662 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002663 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002664 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002665 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002666
2667 if (spec->kctl_alloc)
2668 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2669
2670 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002671 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002672
2673 return 1;
2674}
2675
Sam Revitch62fe78e2006-05-10 15:09:17 +02002676/*
2677 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2678 * funky external mute control using GPIO pins.
2679 */
2680
2681static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
2682{
2683 unsigned int gpiostate, gpiomask, gpiodir;
2684
2685 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2686 AC_VERB_GET_GPIO_DATA, 0);
2687
2688 if (!muted)
2689 gpiostate |= (1 << pin);
2690 else
2691 gpiostate &= ~(1 << pin);
2692
2693 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2694 AC_VERB_GET_GPIO_MASK, 0);
2695 gpiomask |= (1 << pin);
2696
2697 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2698 AC_VERB_GET_GPIO_DIRECTION, 0);
2699 gpiodir |= (1 << pin);
2700
2701 /* AppleHDA seems to do this -- WTF is this verb?? */
2702 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2703
2704 snd_hda_codec_write(codec, codec->afg, 0,
2705 AC_VERB_SET_GPIO_MASK, gpiomask);
2706 snd_hda_codec_write(codec, codec->afg, 0,
2707 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
2708
2709 msleep(1);
2710
2711 snd_hda_codec_write(codec, codec->afg, 0,
2712 AC_VERB_SET_GPIO_DATA, gpiostate);
2713}
2714
Takashi Iwai314634b2006-09-21 11:56:18 +02002715static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2716 unsigned int event)
2717{
2718 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002719 snd_hda_codec_write_cache(codec, nid, 0,
2720 AC_VERB_SET_UNSOLICITED_ENABLE,
2721 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002722}
2723
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002724static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2725{
2726 int i;
2727 for (i = 0; i < cfg->hp_outs; i++)
2728 if (cfg->hp_pins[i] == nid)
2729 return 1; /* nid is a HP-Out */
2730
2731 return 0; /* nid is not a HP-Out */
2732};
2733
Mattc7d4b2f2005-06-27 14:59:41 +02002734static int stac92xx_init(struct hda_codec *codec)
2735{
2736 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002737 struct auto_pin_cfg *cfg = &spec->autocfg;
2738 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002739
Mattc7d4b2f2005-06-27 14:59:41 +02002740 snd_hda_sequence_write(codec, spec->init);
2741
Takashi Iwai82bc9552006-03-21 11:24:42 +01002742 /* set up pins */
2743 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002744 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002745 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002746 enable_pin_detect(codec, cfg->hp_pins[i],
2747 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002748 /* force to enable the first line-out; the others are set up
2749 * in unsol_event
2750 */
2751 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2752 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002753 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002754 /* fake event to set up pins */
2755 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2756 } else {
2757 stac92xx_auto_init_multi_out(codec);
2758 stac92xx_auto_init_hp_out(codec);
2759 }
2760 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002761 hda_nid_t nid = cfg->input_pins[i];
2762 if (nid) {
2763 unsigned int pinctl = AC_PINCTL_IN_EN;
2764 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2765 pinctl |= stac92xx_get_vref(codec, nid);
2766 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2767 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002768 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002769 for (i = 0; i < spec->num_dmics; i++)
2770 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2771 AC_PINCTL_IN_EN);
2772 for (i = 0; i < spec->num_pwrs; i++) {
2773 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2774 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2775 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2776 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2777 /* outputs are only ports capable of power management
2778 * any attempts on powering down a input port cause the
2779 * referenced VREF to act quirky.
2780 */
2781 if (pinctl & AC_PINCTL_IN_EN)
2782 continue;
2783 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2784 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2785 }
Matt Porter8b657272006-10-26 17:12:59 +02002786
Takashi Iwai82bc9552006-03-21 11:24:42 +01002787 if (cfg->dig_out_pin)
2788 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2789 AC_PINCTL_OUT_EN);
2790 if (cfg->dig_in_pin)
2791 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2792 AC_PINCTL_IN_EN);
2793
Sam Revitch62fe78e2006-05-10 15:09:17 +02002794 if (spec->gpio_mute) {
2795 stac922x_gpio_mute(codec, 0, 0);
2796 stac922x_gpio_mute(codec, 1, 0);
2797 }
2798
Mattc7d4b2f2005-06-27 14:59:41 +02002799 return 0;
2800}
2801
Matt2f2f4252005-04-13 14:45:30 +02002802static void stac92xx_free(struct hda_codec *codec)
2803{
Mattc7d4b2f2005-06-27 14:59:41 +02002804 struct sigmatel_spec *spec = codec->spec;
2805 int i;
2806
2807 if (! spec)
2808 return;
2809
2810 if (spec->kctl_alloc) {
2811 for (i = 0; i < spec->num_kctl_used; i++)
2812 kfree(spec->kctl_alloc[i].name);
2813 kfree(spec->kctl_alloc);
2814 }
2815
Richard Fish11b44bb2006-08-23 18:31:34 +02002816 if (spec->bios_pin_configs)
2817 kfree(spec->bios_pin_configs);
2818
Mattc7d4b2f2005-06-27 14:59:41 +02002819 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002820}
2821
Matt4e550962005-07-04 17:51:39 +02002822static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2823 unsigned int flag)
2824{
2825 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2826 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002827
Takashi Iwaif9acba42007-05-29 18:01:06 +02002828 if (pin_ctl & AC_PINCTL_IN_EN) {
2829 /*
2830 * we need to check the current set-up direction of
2831 * shared input pins since they can be switched via
2832 * "xxx as Output" mixer switch
2833 */
2834 struct sigmatel_spec *spec = codec->spec;
2835 struct auto_pin_cfg *cfg = &spec->autocfg;
2836 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2837 spec->line_switch) ||
2838 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2839 spec->mic_switch))
2840 return;
2841 }
2842
Steve Longerbeam7b043892007-05-03 20:50:03 +02002843 /* if setting pin direction bits, clear the current
2844 direction bits first */
2845 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2846 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2847
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002848 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002849 AC_VERB_SET_PIN_WIDGET_CONTROL,
2850 pin_ctl | flag);
2851}
2852
2853static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2854 unsigned int flag)
2855{
2856 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2857 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002858 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002859 AC_VERB_SET_PIN_WIDGET_CONTROL,
2860 pin_ctl & ~flag);
2861}
2862
Jiang Zhe40c1d302007-11-12 13:05:16 +01002863static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02002864{
2865 if (!nid)
2866 return 0;
2867 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01002868 & (1 << 31)) {
2869 unsigned int pinctl;
2870 pinctl = snd_hda_codec_read(codec, nid, 0,
2871 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2872 if (pinctl & AC_PINCTL_IN_EN)
2873 return 0; /* mic- or line-input */
2874 else
2875 return 1; /* HP-output */
2876 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002877 return 0;
2878}
2879
2880static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02002881{
2882 struct sigmatel_spec *spec = codec->spec;
2883 struct auto_pin_cfg *cfg = &spec->autocfg;
2884 int i, presence;
2885
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002886 presence = 0;
2887 for (i = 0; i < cfg->hp_outs; i++) {
Jiang Zhe40c1d302007-11-12 13:05:16 +01002888 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwai314634b2006-09-21 11:56:18 +02002889 if (presence)
2890 break;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002891 }
Matt4e550962005-07-04 17:51:39 +02002892
2893 if (presence) {
2894 /* disable lineouts, enable hp */
2895 for (i = 0; i < cfg->line_outs; i++)
2896 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
2897 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002898 for (i = 0; i < cfg->speaker_outs; i++)
2899 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
2900 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002901 } else {
2902 /* enable lineouts, disable hp */
2903 for (i = 0; i < cfg->line_outs; i++)
2904 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
2905 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002906 for (i = 0; i < cfg->speaker_outs; i++)
2907 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
2908 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002909 }
2910}
2911
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002912static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
2913{
2914 struct sigmatel_spec *spec = codec->spec;
2915 hda_nid_t nid = spec->pwr_nids[idx];
2916 int presence, val;
2917 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
2918 & 0x000000ff;
2919 presence = get_hp_pin_presence(codec, nid);
2920 idx = 1 << idx;
2921
2922 if (presence)
2923 val &= ~idx;
2924 else
2925 val |= idx;
2926
2927 /* power down unused output ports */
2928 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
2929};
2930
Takashi Iwai314634b2006-09-21 11:56:18 +02002931static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
2932{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002933 struct sigmatel_spec *spec = codec->spec;
2934 int idx = res >> 26 & 0x0f;
2935
2936 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002937 case STAC_HP_EVENT:
2938 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002939 /* fallthru */
2940 case STAC_PWR_EVENT:
2941 if (spec->num_pwrs > 0)
2942 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02002943 }
2944}
2945
Takashi Iwaicb53c622007-08-10 17:21:45 +02002946#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002947static int stac92xx_resume(struct hda_codec *codec)
2948{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002949 struct sigmatel_spec *spec = codec->spec;
2950
Richard Fish11b44bb2006-08-23 18:31:34 +02002951 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002952 snd_hda_sequence_write(codec, spec->init);
2953 if (spec->gpio_mute) {
2954 stac922x_gpio_mute(codec, 0, 0);
2955 stac922x_gpio_mute(codec, 1, 0);
2956 }
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002957 snd_hda_codec_resume_amp(codec);
2958 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002959 /* invoke unsolicited event to reset the HP state */
2960 if (spec->hp_detect)
2961 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02002962 return 0;
2963}
2964#endif
2965
Matt2f2f4252005-04-13 14:45:30 +02002966static struct hda_codec_ops stac92xx_patch_ops = {
2967 .build_controls = stac92xx_build_controls,
2968 .build_pcms = stac92xx_build_pcms,
2969 .init = stac92xx_init,
2970 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02002971 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002972#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002973 .resume = stac92xx_resume,
2974#endif
Matt2f2f4252005-04-13 14:45:30 +02002975};
2976
2977static int patch_stac9200(struct hda_codec *codec)
2978{
2979 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002980 int err;
Matt2f2f4252005-04-13 14:45:30 +02002981
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002982 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02002983 if (spec == NULL)
2984 return -ENOMEM;
2985
2986 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002987 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002988 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002989 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
2990 stac9200_models,
2991 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02002992 if (spec->board_config < 0) {
2993 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
2994 err = stac92xx_save_bios_config_regs(codec);
2995 if (err < 0) {
2996 stac92xx_free(codec);
2997 return err;
2998 }
2999 spec->pin_configs = spec->bios_pin_configs;
3000 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003001 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3002 stac92xx_set_config_regs(codec);
3003 }
Matt2f2f4252005-04-13 14:45:30 +02003004
3005 spec->multiout.max_channels = 2;
3006 spec->multiout.num_dacs = 1;
3007 spec->multiout.dac_nids = stac9200_dac_nids;
3008 spec->adc_nids = stac9200_adc_nids;
3009 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003010 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003011 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003012 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003013 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003014
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003015 if (spec->board_config == STAC_9200_GATEWAY)
3016 spec->init = stac9200_eapd_init;
3017 else
3018 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003019 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003020
3021 err = stac9200_parse_auto_config(codec);
3022 if (err < 0) {
3023 stac92xx_free(codec);
3024 return err;
3025 }
Matt2f2f4252005-04-13 14:45:30 +02003026
3027 codec->patch_ops = stac92xx_patch_ops;
3028
3029 return 0;
3030}
3031
Tobin Davis8e21c342007-01-08 11:04:17 +01003032static int patch_stac925x(struct hda_codec *codec)
3033{
3034 struct sigmatel_spec *spec;
3035 int err;
3036
3037 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3038 if (spec == NULL)
3039 return -ENOMEM;
3040
3041 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003042 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003043 spec->pin_nids = stac925x_pin_nids;
3044 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3045 stac925x_models,
3046 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003047 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003048 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003049 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3050 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003051 err = stac92xx_save_bios_config_regs(codec);
3052 if (err < 0) {
3053 stac92xx_free(codec);
3054 return err;
3055 }
3056 spec->pin_configs = spec->bios_pin_configs;
3057 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3058 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3059 stac92xx_set_config_regs(codec);
3060 }
3061
3062 spec->multiout.max_channels = 2;
3063 spec->multiout.num_dacs = 1;
3064 spec->multiout.dac_nids = stac925x_dac_nids;
3065 spec->adc_nids = stac925x_adc_nids;
3066 spec->mux_nids = stac925x_mux_nids;
3067 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003068 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003069 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003070 switch (codec->vendor_id) {
3071 case 0x83847632: /* STAC9202 */
3072 case 0x83847633: /* STAC9202D */
3073 case 0x83847636: /* STAC9251 */
3074 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003075 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003076 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003077 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3078 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003079 break;
3080 default:
3081 spec->num_dmics = 0;
3082 break;
3083 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003084
3085 spec->init = stac925x_core_init;
3086 spec->mixer = stac925x_mixer;
3087
3088 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003089 if (!err) {
3090 if (spec->board_config < 0) {
3091 printk(KERN_WARNING "hda_codec: No auto-config is "
3092 "available, default to model=ref\n");
3093 spec->board_config = STAC_925x_REF;
3094 goto again;
3095 }
3096 err = -EINVAL;
3097 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003098 if (err < 0) {
3099 stac92xx_free(codec);
3100 return err;
3101 }
3102
3103 codec->patch_ops = stac92xx_patch_ops;
3104
3105 return 0;
3106}
3107
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003108static struct hda_input_mux stac92hd73xx_dmux = {
3109 .num_items = 4,
3110 .items = {
3111 { "Analog Inputs", 0x0b },
3112 { "CD", 0x08 },
3113 { "Digital Mic 1", 0x09 },
3114 { "Digital Mic 2", 0x0a },
3115 }
3116};
3117
3118static int patch_stac92hd73xx(struct hda_codec *codec)
3119{
3120 struct sigmatel_spec *spec;
3121 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3122 int err = 0;
3123
3124 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3125 if (spec == NULL)
3126 return -ENOMEM;
3127
3128 codec->spec = spec;
3129 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3130 spec->pin_nids = stac92hd73xx_pin_nids;
3131 spec->board_config = snd_hda_check_board_config(codec,
3132 STAC_92HD73XX_MODELS,
3133 stac92hd73xx_models,
3134 stac92hd73xx_cfg_tbl);
3135again:
3136 if (spec->board_config < 0) {
3137 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3138 " STAC92HD73XX, using BIOS defaults\n");
3139 err = stac92xx_save_bios_config_regs(codec);
3140 if (err < 0) {
3141 stac92xx_free(codec);
3142 return err;
3143 }
3144 spec->pin_configs = spec->bios_pin_configs;
3145 } else {
3146 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3147 stac92xx_set_config_regs(codec);
3148 }
3149
3150 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3151 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3152
3153 if (spec->multiout.num_dacs < 0) {
3154 printk(KERN_WARNING "hda_codec: Could not determine "
3155 "number of channels defaulting to DAC count\n");
3156 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3157 }
3158
3159 switch (spec->multiout.num_dacs) {
3160 case 0x3: /* 6 Channel */
3161 spec->mixer = stac92hd73xx_6ch_mixer;
3162 spec->init = stac92hd73xx_6ch_core_init;
3163 break;
3164 case 0x4: /* 8 Channel */
3165 spec->multiout.hp_nid = 0x18;
3166 spec->mixer = stac92hd73xx_8ch_mixer;
3167 spec->init = stac92hd73xx_8ch_core_init;
3168 break;
3169 case 0x5: /* 10 Channel */
3170 spec->multiout.hp_nid = 0x19;
3171 spec->mixer = stac92hd73xx_10ch_mixer;
3172 spec->init = stac92hd73xx_10ch_core_init;
3173 };
3174
3175 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3176 spec->aloopback_mask = 0x01;
3177 spec->aloopback_shift = 8;
3178
3179 spec->mux_nids = stac92hd73xx_mux_nids;
3180 spec->adc_nids = stac92hd73xx_adc_nids;
3181 spec->dmic_nids = stac92hd73xx_dmic_nids;
3182 spec->dmux_nids = stac92hd73xx_dmux_nids;
3183
3184 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3185 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3186 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003187 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003188 spec->dinput_mux = &stac92hd73xx_dmux;
3189 /* GPIO0 High = Enable EAPD */
3190 spec->gpio_mask = spec->gpio_data = 0x000001;
3191 stac92xx_enable_gpio_mask(codec);
3192
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003193 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3194 spec->pwr_nids = stac92hd73xx_pwr_nids;
3195
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003196 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3197
3198 if (!err) {
3199 if (spec->board_config < 0) {
3200 printk(KERN_WARNING "hda_codec: No auto-config is "
3201 "available, default to model=ref\n");
3202 spec->board_config = STAC_92HD73XX_REF;
3203 goto again;
3204 }
3205 err = -EINVAL;
3206 }
3207
3208 if (err < 0) {
3209 stac92xx_free(codec);
3210 return err;
3211 }
3212
3213 codec->patch_ops = stac92xx_patch_ops;
3214
3215 return 0;
3216}
3217
Matthew Ranostaye035b842007-11-06 11:53:55 +01003218static int patch_stac92hd71bxx(struct hda_codec *codec)
3219{
3220 struct sigmatel_spec *spec;
3221 int err = 0;
3222
3223 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3224 if (spec == NULL)
3225 return -ENOMEM;
3226
3227 codec->spec = spec;
3228 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3229 spec->pin_nids = stac92hd71bxx_pin_nids;
3230 spec->board_config = snd_hda_check_board_config(codec,
3231 STAC_92HD71BXX_MODELS,
3232 stac92hd71bxx_models,
3233 stac92hd71bxx_cfg_tbl);
3234again:
3235 if (spec->board_config < 0) {
3236 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3237 " STAC92HD71BXX, using BIOS defaults\n");
3238 err = stac92xx_save_bios_config_regs(codec);
3239 if (err < 0) {
3240 stac92xx_free(codec);
3241 return err;
3242 }
3243 spec->pin_configs = spec->bios_pin_configs;
3244 } else {
3245 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3246 stac92xx_set_config_regs(codec);
3247 }
3248
Matthew Ranostay541eee82007-12-14 12:08:04 +01003249 switch (codec->vendor_id) {
3250 case 0x111d76b6: /* 4 Port without Analog Mixer */
3251 case 0x111d76b7:
3252 case 0x111d76b4: /* 6 Port without Analog Mixer */
3253 case 0x111d76b5:
3254 spec->mixer = stac92hd71bxx_mixer;
3255 spec->init = stac92hd71bxx_core_init;
3256 break;
3257 default:
3258 spec->mixer = stac92hd71bxx_analog_mixer;
3259 spec->init = stac92hd71bxx_analog_core_init;
3260 }
3261
3262 spec->aloopback_mask = 0x20;
3263 spec->aloopback_shift = 0;
3264
Matthew Ranostaye035b842007-11-06 11:53:55 +01003265 spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
3266 stac92xx_enable_gpio_mask(codec);
3267
Matthew Ranostaye035b842007-11-06 11:53:55 +01003268 spec->mux_nids = stac92hd71bxx_mux_nids;
3269 spec->adc_nids = stac92hd71bxx_adc_nids;
3270 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003271 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003272
3273 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3274 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3275 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003276 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003277
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003278 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3279 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3280
Matthew Ranostaye035b842007-11-06 11:53:55 +01003281 spec->multiout.num_dacs = 2;
3282 spec->multiout.hp_nid = 0x11;
3283 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3284
3285 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3286 if (!err) {
3287 if (spec->board_config < 0) {
3288 printk(KERN_WARNING "hda_codec: No auto-config is "
3289 "available, default to model=ref\n");
3290 spec->board_config = STAC_92HD71BXX_REF;
3291 goto again;
3292 }
3293 err = -EINVAL;
3294 }
3295
3296 if (err < 0) {
3297 stac92xx_free(codec);
3298 return err;
3299 }
3300
3301 codec->patch_ops = stac92xx_patch_ops;
3302
3303 return 0;
3304};
3305
Matt2f2f4252005-04-13 14:45:30 +02003306static int patch_stac922x(struct hda_codec *codec)
3307{
3308 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003309 int err;
Matt2f2f4252005-04-13 14:45:30 +02003310
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003311 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003312 if (spec == NULL)
3313 return -ENOMEM;
3314
3315 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003316 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003317 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003318 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3319 stac922x_models,
3320 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003321 if (spec->board_config == STAC_INTEL_MAC_V3) {
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003322 spec->gpio_mute = 1;
3323 /* Intel Macs have all same PCI SSID, so we need to check
3324 * codec SSID to distinguish the exact models
3325 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003326 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003327 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003328
3329 case 0x106b0800:
3330 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003331 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003332 case 0x106b0600:
3333 case 0x106b0700:
3334 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003335 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003336 case 0x106b0e00:
3337 case 0x106b0f00:
3338 case 0x106b1600:
3339 case 0x106b1700:
3340 case 0x106b0200:
3341 case 0x106b1e00:
3342 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003343 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003344 case 0x106b1a00:
3345 case 0x00000100:
3346 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003347 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003348 case 0x106b0a00:
3349 case 0x106b2200:
3350 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003351 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003352 }
3353 }
3354
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003355 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003356 if (spec->board_config < 0) {
3357 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3358 "using BIOS defaults\n");
3359 err = stac92xx_save_bios_config_regs(codec);
3360 if (err < 0) {
3361 stac92xx_free(codec);
3362 return err;
3363 }
3364 spec->pin_configs = spec->bios_pin_configs;
3365 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003366 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3367 stac92xx_set_config_regs(codec);
3368 }
Matt2f2f4252005-04-13 14:45:30 +02003369
Matt2f2f4252005-04-13 14:45:30 +02003370 spec->adc_nids = stac922x_adc_nids;
3371 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003372 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003373 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003374 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003375 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003376
3377 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003378 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003379
3380 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003381
Matt Porter3cc08dc2006-01-23 15:27:49 +01003382 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003383 if (!err) {
3384 if (spec->board_config < 0) {
3385 printk(KERN_WARNING "hda_codec: No auto-config is "
3386 "available, default to model=ref\n");
3387 spec->board_config = STAC_D945_REF;
3388 goto again;
3389 }
3390 err = -EINVAL;
3391 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003392 if (err < 0) {
3393 stac92xx_free(codec);
3394 return err;
3395 }
3396
3397 codec->patch_ops = stac92xx_patch_ops;
3398
Takashi Iwai807a46362007-05-29 19:01:37 +02003399 /* Fix Mux capture level; max to 2 */
3400 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3401 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3402 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3403 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3404 (0 << AC_AMPCAP_MUTE_SHIFT));
3405
Matt Porter3cc08dc2006-01-23 15:27:49 +01003406 return 0;
3407}
3408
3409static int patch_stac927x(struct hda_codec *codec)
3410{
3411 struct sigmatel_spec *spec;
3412 int err;
3413
3414 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3415 if (spec == NULL)
3416 return -ENOMEM;
3417
3418 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003419 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003420 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003421 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3422 stac927x_models,
3423 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003424 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003425 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3426 if (spec->board_config < 0)
3427 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3428 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003429 err = stac92xx_save_bios_config_regs(codec);
3430 if (err < 0) {
3431 stac92xx_free(codec);
3432 return err;
3433 }
3434 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003435 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003436 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3437 stac92xx_set_config_regs(codec);
3438 }
3439
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003440 spec->adc_nids = stac927x_adc_nids;
3441 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3442 spec->mux_nids = stac927x_mux_nids;
3443 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
3444 spec->multiout.dac_nids = spec->dac_nids;
3445
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003446 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003447 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003448 case STAC_D965_5ST:
3449 /* GPIO0 High = Enable EAPD */
3450 spec->gpio_mask = spec->gpio_data = 0x00000001;
3451 spec->num_dmics = 0;
3452
Tobin Davis93ed1502006-09-01 21:03:12 +02003453 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003454 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003455 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003456 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003457 /* correct the front output jack as a hp out */
3458 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003459 /* correct the front input jack as a mic */
3460 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3461 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003462 case STAC_DELL_3ST:
3463 /* GPIO2 High = Enable EAPD */
3464 spec->gpio_mask = spec->gpio_data = 0x00000004;
3465 spec->dmic_nids = stac927x_dmic_nids;
3466 spec->num_dmics = STAC927X_NUM_DMICS;
3467
Tobin Davis93ed1502006-09-01 21:03:12 +02003468 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003469 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003470 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003471 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003472 break;
3473 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003474 /* GPIO0 High = Enable EAPD */
3475 spec->gpio_mask = spec->gpio_data = 0x00000001;
3476 spec->num_dmics = 0;
3477
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003478 spec->init = stac927x_core_init;
3479 spec->mixer = stac927x_mixer;
3480 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003481
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003482 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003483 spec->aloopback_mask = 0x40;
3484 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003485
Takashi Iwai82599802007-07-31 15:56:24 +02003486 stac92xx_enable_gpio_mask(codec);
Matt Porter3cc08dc2006-01-23 15:27:49 +01003487 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003488 if (!err) {
3489 if (spec->board_config < 0) {
3490 printk(KERN_WARNING "hda_codec: No auto-config is "
3491 "available, default to model=ref\n");
3492 spec->board_config = STAC_D965_REF;
3493 goto again;
3494 }
3495 err = -EINVAL;
3496 }
Mattc7d4b2f2005-06-27 14:59:41 +02003497 if (err < 0) {
3498 stac92xx_free(codec);
3499 return err;
3500 }
Matt2f2f4252005-04-13 14:45:30 +02003501
3502 codec->patch_ops = stac92xx_patch_ops;
3503
3504 return 0;
3505}
3506
Matt Porterf3302a52006-07-31 12:49:34 +02003507static int patch_stac9205(struct hda_codec *codec)
3508{
3509 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003510 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003511
3512 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3513 if (spec == NULL)
3514 return -ENOMEM;
3515
3516 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003517 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003518 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003519 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3520 stac9205_models,
3521 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003522 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003523 if (spec->board_config < 0) {
3524 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3525 err = stac92xx_save_bios_config_regs(codec);
3526 if (err < 0) {
3527 stac92xx_free(codec);
3528 return err;
3529 }
3530 spec->pin_configs = spec->bios_pin_configs;
3531 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003532 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3533 stac92xx_set_config_regs(codec);
3534 }
3535
3536 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003537 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003538 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003539 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003540 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003541 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003542 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003543 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003544 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003545
3546 spec->init = stac9205_core_init;
3547 spec->mixer = stac9205_mixer;
3548
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003549 spec->aloopback_mask = 0x40;
3550 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003551 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003552
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003553 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003554 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003555 /* Enable SPDIF in/out */
3556 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3557 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003558
Takashi Iwai82599802007-07-31 15:56:24 +02003559 spec->gpio_mask = 0x00000007; /* GPIO0-2 */
Matthew Ranostay87d48362007-07-17 11:52:24 +02003560 /* GPIO0 High = EAPD, GPIO1 Low = DRM,
3561 * GPIO2 High = Headphone Mute
3562 */
Takashi Iwai82599802007-07-31 15:56:24 +02003563 spec->gpio_data = 0x00000005;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003564 break;
3565 default:
3566 /* GPIO0 High = EAPD */
3567 spec->gpio_mask = spec->gpio_data = 0x00000001;
3568 break;
3569 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003570
Takashi Iwai82599802007-07-31 15:56:24 +02003571 stac92xx_enable_gpio_mask(codec);
Matt Porterf3302a52006-07-31 12:49:34 +02003572 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003573 if (!err) {
3574 if (spec->board_config < 0) {
3575 printk(KERN_WARNING "hda_codec: No auto-config is "
3576 "available, default to model=ref\n");
3577 spec->board_config = STAC_9205_REF;
3578 goto again;
3579 }
3580 err = -EINVAL;
3581 }
Matt Porterf3302a52006-07-31 12:49:34 +02003582 if (err < 0) {
3583 stac92xx_free(codec);
3584 return err;
3585 }
3586
3587 codec->patch_ops = stac92xx_patch_ops;
3588
3589 return 0;
3590}
3591
Matt2f2f4252005-04-13 14:45:30 +02003592/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003593 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003594 */
3595
Guillaume Munch99ccc562006-08-16 19:35:12 +02003596/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003597static hda_nid_t vaio_dacs[] = { 0x2 };
3598#define VAIO_HP_DAC 0x5
3599static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3600static hda_nid_t vaio_mux_nids[] = { 0x15 };
3601
3602static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003603 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003604 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003605 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003606 { "Mic Jack", 0x1 },
3607 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003608 { "PCM", 0x3 },
3609 }
3610};
3611
3612static struct hda_verb vaio_init[] = {
3613 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003614 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003615 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3616 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3617 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3618 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003619 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003620 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3621 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3622 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3623 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3625 {}
3626};
3627
Guillaume Munch6d859062006-08-22 17:15:47 +02003628static struct hda_verb vaio_ar_init[] = {
3629 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3630 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3631 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3632 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3633/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3634 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003635 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003636 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3637 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3638/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3639 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3640 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3641 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3642 {}
3643};
3644
Takashi Iwaidb064e52006-03-16 16:04:58 +01003645/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003646static struct hda_bind_ctls vaio_bind_master_vol = {
3647 .ops = &snd_hda_bind_vol,
3648 .values = {
3649 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3650 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3651 0
3652 },
3653};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003654
3655/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003656static struct hda_bind_ctls vaio_bind_master_sw = {
3657 .ops = &snd_hda_bind_sw,
3658 .values = {
3659 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3660 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3661 0,
3662 },
3663};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003664
3665static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003666 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3667 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003668 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3669 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3670 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3671 {
3672 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3673 .name = "Capture Source",
3674 .count = 1,
3675 .info = stac92xx_mux_enum_info,
3676 .get = stac92xx_mux_enum_get,
3677 .put = stac92xx_mux_enum_put,
3678 },
3679 {}
3680};
3681
Guillaume Munch6d859062006-08-22 17:15:47 +02003682static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003683 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3684 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003685 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3686 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3687 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3688 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3689 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3690 {
3691 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3692 .name = "Capture Source",
3693 .count = 1,
3694 .info = stac92xx_mux_enum_info,
3695 .get = stac92xx_mux_enum_get,
3696 .put = stac92xx_mux_enum_put,
3697 },
3698 {}
3699};
3700
3701static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003702 .build_controls = stac92xx_build_controls,
3703 .build_pcms = stac92xx_build_pcms,
3704 .init = stac92xx_init,
3705 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003706#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003707 .resume = stac92xx_resume,
3708#endif
3709};
3710
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003711static int stac9872_vaio_init(struct hda_codec *codec)
3712{
3713 int err;
3714
3715 err = stac92xx_init(codec);
3716 if (err < 0)
3717 return err;
3718 if (codec->patch_ops.unsol_event)
3719 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3720 return 0;
3721}
3722
3723static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3724{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003725 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003726 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3727 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3728 } else {
3729 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3730 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3731 }
3732}
3733
3734static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3735{
3736 switch (res >> 26) {
3737 case STAC_HP_EVENT:
3738 stac9872_vaio_hp_detect(codec, res);
3739 break;
3740 }
3741}
3742
3743static struct hda_codec_ops stac9872_vaio_patch_ops = {
3744 .build_controls = stac92xx_build_controls,
3745 .build_pcms = stac92xx_build_pcms,
3746 .init = stac9872_vaio_init,
3747 .free = stac92xx_free,
3748 .unsol_event = stac9872_vaio_unsol_event,
3749#ifdef CONFIG_PM
3750 .resume = stac92xx_resume,
3751#endif
3752};
3753
Guillaume Munch6d859062006-08-22 17:15:47 +02003754enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3755 CXD9872RD_VAIO,
3756 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3757 STAC9872AK_VAIO,
3758 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3759 STAC9872K_VAIO,
3760 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003761 CXD9872AKD_VAIO,
3762 STAC_9872_MODELS,
3763};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003764
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003765static const char *stac9872_models[STAC_9872_MODELS] = {
3766 [CXD9872RD_VAIO] = "vaio",
3767 [CXD9872AKD_VAIO] = "vaio-ar",
3768};
3769
3770static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3771 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3772 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3773 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003774 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003775 {}
3776};
3777
Guillaume Munch6d859062006-08-22 17:15:47 +02003778static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003779{
3780 struct sigmatel_spec *spec;
3781 int board_config;
3782
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003783 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3784 stac9872_models,
3785 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003786 if (board_config < 0)
3787 /* unknown config, let generic-parser do its job... */
3788 return snd_hda_parse_generic_codec(codec);
3789
3790 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3791 if (spec == NULL)
3792 return -ENOMEM;
3793
3794 codec->spec = spec;
3795 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003796 case CXD9872RD_VAIO:
3797 case STAC9872AK_VAIO:
3798 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003799 spec->mixer = vaio_mixer;
3800 spec->init = vaio_init;
3801 spec->multiout.max_channels = 2;
3802 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3803 spec->multiout.dac_nids = vaio_dacs;
3804 spec->multiout.hp_nid = VAIO_HP_DAC;
3805 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3806 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003807 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003808 spec->input_mux = &vaio_mux;
3809 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003810 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003811 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003812
3813 case CXD9872AKD_VAIO:
3814 spec->mixer = vaio_ar_mixer;
3815 spec->init = vaio_ar_init;
3816 spec->multiout.max_channels = 2;
3817 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3818 spec->multiout.dac_nids = vaio_dacs;
3819 spec->multiout.hp_nid = VAIO_HP_DAC;
3820 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003821 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02003822 spec->adc_nids = vaio_adcs;
3823 spec->input_mux = &vaio_mux;
3824 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003825 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003826 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003827 }
3828
Takashi Iwaidb064e52006-03-16 16:04:58 +01003829 return 0;
3830}
3831
3832
3833/*
Matt2f2f4252005-04-13 14:45:30 +02003834 * patch entries
3835 */
3836struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3837 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3838 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3839 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3840 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3841 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3842 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3843 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003844 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3845 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3846 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3847 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3848 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
3849 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01003850 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
3851 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
3852 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
3853 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
3854 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
3855 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
3856 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
3857 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
3858 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
3859 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01003860 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
3861 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
3862 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
3863 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
3864 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
3865 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02003866 /* The following does not take into account .id=0x83847661 when subsys =
3867 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
3868 * currently not fully supported.
3869 */
3870 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
3871 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
3872 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02003873 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
3874 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
3875 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
3876 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
3877 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
3878 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
3879 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
3880 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01003881 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
3882 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003883 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01003884 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
3885 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
3886 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
3887 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
3888 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
3889 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
3890 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
3891 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
3892 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02003893 {} /* terminator */
3894};