blob: b8e69a1b93f02597acb22ef971fc8580696fb396 [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"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010035#include "hda_patch.h"
Matt2f2f4252005-04-13 14:45:30 +020036
Matt4e550962005-07-04 17:51:39 +020037#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010038#define STAC_PWR_EVENT 0x20
39#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020040
Takashi Iwaif5fcc132006-11-24 17:07:44 +010041enum {
42 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010043 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020044 STAC_9200_DELL_D21,
45 STAC_9200_DELL_D22,
46 STAC_9200_DELL_D23,
47 STAC_9200_DELL_M21,
48 STAC_9200_DELL_M22,
49 STAC_9200_DELL_M23,
50 STAC_9200_DELL_M24,
51 STAC_9200_DELL_M25,
52 STAC_9200_DELL_M26,
53 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020054 STAC_9200_GATEWAY,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010055 STAC_9200_MODELS
56};
57
58enum {
59 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020060 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020061 STAC_9205_DELL_M43,
62 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010063 STAC_9205_MODELS
64};
65
66enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010067 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010068 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010069 STAC_92HD73XX_MODELS
70};
71
72enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010073 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010074 STAC_DELL_M4_1,
75 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010076 STAC_92HD71BXX_MODELS
77};
78
79enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010080 STAC_925x_REF,
81 STAC_M2_2,
82 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020083 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010084 STAC_925x_MODELS
85};
86
87enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010088 STAC_D945_REF,
89 STAC_D945GTP3,
90 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020091 STAC_INTEL_MAC_V1,
92 STAC_INTEL_MAC_V2,
93 STAC_INTEL_MAC_V3,
94 STAC_INTEL_MAC_V4,
95 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020096 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010097 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010098 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010099 STAC_MACBOOK_PRO_V1,
100 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200101 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200102 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200103 STAC_922X_DELL_D81,
104 STAC_922X_DELL_D82,
105 STAC_922X_DELL_M81,
106 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100107 STAC_922X_MODELS
108};
109
110enum {
111 STAC_D965_REF,
112 STAC_D965_3ST,
113 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200114 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100115 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100116 STAC_927X_MODELS
117};
Matt Porter403d1942005-11-29 15:00:51 +0100118
Matt2f2f4252005-04-13 14:45:30 +0200119struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100120 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200121 unsigned int num_mixers;
122
Matt Porter403d1942005-11-29 15:00:51 +0100123 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200124 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100125 unsigned int line_switch: 1;
126 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100127 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100128 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200129
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +0100130 /* gpio lines */
131 unsigned int gpio_mask;
132 unsigned int gpio_dir;
133 unsigned int gpio_data;
134 unsigned int gpio_mute;
135
136 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100137 unsigned char aloopback_mask;
138 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200139
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100140 /* power management */
141 unsigned int num_pwrs;
142 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100143 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100144
Matt2f2f4252005-04-13 14:45:30 +0200145 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100146 struct hda_input_mux *mono_mux;
147 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200148 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100149 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200150
151 /* capture */
152 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200153 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200154 hda_nid_t *mux_nids;
155 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200156 hda_nid_t *dmic_nids;
157 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100158 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100159 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200160 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100161 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200162
Matt2f2f4252005-04-13 14:45:30 +0200163 /* pin widgets */
164 hda_nid_t *pin_nids;
165 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200166 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200167 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200168
169 /* codec specific stuff */
170 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100171 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200172
173 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200174 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100175 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200176 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100177 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200178
Matt Porter403d1942005-11-29 15:00:51 +0100179 /* i/o switches */
180 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200181 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200182 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200183
Mattc7d4b2f2005-06-27 14:59:41 +0200184 struct hda_pcm pcm_rec[2]; /* PCM information */
185
186 /* dynamic controls and input_mux */
187 struct auto_pin_cfg autocfg;
188 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100189 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200190 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200191 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100192 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200193};
194
195static hda_nid_t stac9200_adc_nids[1] = {
196 0x03,
197};
198
199static hda_nid_t stac9200_mux_nids[1] = {
200 0x0c,
201};
202
203static hda_nid_t stac9200_dac_nids[1] = {
204 0x02,
205};
206
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100207static hda_nid_t stac92hd73xx_pwr_nids[8] = {
208 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
209 0x0f, 0x10, 0x11
210};
211
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100212static hda_nid_t stac92hd73xx_adc_nids[2] = {
213 0x1a, 0x1b
214};
215
216#define STAC92HD73XX_NUM_DMICS 2
217static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
218 0x13, 0x14, 0
219};
220
221#define STAC92HD73_DAC_COUNT 5
222static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
223 0x15, 0x16, 0x17, 0x18, 0x19,
224};
225
226static hda_nid_t stac92hd73xx_mux_nids[4] = {
227 0x28, 0x29, 0x2a, 0x2b,
228};
229
230static hda_nid_t stac92hd73xx_dmux_nids[2] = {
231 0x20, 0x21,
232};
233
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100234static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
235 0x0a, 0x0d, 0x0f
236};
237
Matthew Ranostaye035b842007-11-06 11:53:55 +0100238static hda_nid_t stac92hd71bxx_adc_nids[2] = {
239 0x12, 0x13,
240};
241
242static hda_nid_t stac92hd71bxx_mux_nids[2] = {
243 0x1a, 0x1b
244};
245
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100246static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
247 0x1c,
248};
249
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100250static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100251 0x10, /*0x11, */
252};
253
254#define STAC92HD71BXX_NUM_DMICS 2
255static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
256 0x18, 0x19, 0
257};
258
Tobin Davis8e21c342007-01-08 11:04:17 +0100259static hda_nid_t stac925x_adc_nids[1] = {
260 0x03,
261};
262
263static hda_nid_t stac925x_mux_nids[1] = {
264 0x0f,
265};
266
267static hda_nid_t stac925x_dac_nids[1] = {
268 0x02,
269};
270
Takashi Iwaif6e98522007-10-16 14:27:04 +0200271#define STAC925X_NUM_DMICS 1
272static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
273 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200274};
275
Takashi Iwai1697055e2007-12-18 18:05:52 +0100276static hda_nid_t stac925x_dmux_nids[1] = {
277 0x14,
278};
279
Matt2f2f4252005-04-13 14:45:30 +0200280static hda_nid_t stac922x_adc_nids[2] = {
281 0x06, 0x07,
282};
283
284static hda_nid_t stac922x_mux_nids[2] = {
285 0x12, 0x13,
286};
287
Matt Porter3cc08dc2006-01-23 15:27:49 +0100288static hda_nid_t stac927x_adc_nids[3] = {
289 0x07, 0x08, 0x09
290};
291
292static hda_nid_t stac927x_mux_nids[3] = {
293 0x15, 0x16, 0x17
294};
295
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100296static hda_nid_t stac927x_dac_nids[6] = {
297 0x02, 0x03, 0x04, 0x05, 0x06, 0
298};
299
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100300static hda_nid_t stac927x_dmux_nids[1] = {
301 0x1b,
302};
303
Matthew Ranostay7f168592007-10-18 17:38:17 +0200304#define STAC927X_NUM_DMICS 2
305static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
306 0x13, 0x14, 0
307};
308
Matt Porterf3302a52006-07-31 12:49:34 +0200309static hda_nid_t stac9205_adc_nids[2] = {
310 0x12, 0x13
311};
312
313static hda_nid_t stac9205_mux_nids[2] = {
314 0x19, 0x1a
315};
316
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100317static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100318 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100319};
320
Takashi Iwaif6e98522007-10-16 14:27:04 +0200321#define STAC9205_NUM_DMICS 2
322static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
323 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200324};
325
Mattc7d4b2f2005-06-27 14:59:41 +0200326static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200327 0x08, 0x09, 0x0d, 0x0e,
328 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200329};
330
Tobin Davis8e21c342007-01-08 11:04:17 +0100331static hda_nid_t stac925x_pin_nids[8] = {
332 0x07, 0x08, 0x0a, 0x0b,
333 0x0c, 0x0d, 0x10, 0x11,
334};
335
Matt2f2f4252005-04-13 14:45:30 +0200336static hda_nid_t stac922x_pin_nids[10] = {
337 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
338 0x0f, 0x10, 0x11, 0x15, 0x1b,
339};
340
Matthew Ranostaya7662642008-02-21 07:51:14 +0100341static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100342 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
343 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100344 0x14, 0x1e, 0x22
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100345};
346
Matthew Ranostaye035b842007-11-06 11:53:55 +0100347static hda_nid_t stac92hd71bxx_pin_nids[10] = {
348 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
349 0x0f, 0x14, 0x18, 0x19, 0x1e,
350};
351
Matt Porter3cc08dc2006-01-23 15:27:49 +0100352static hda_nid_t stac927x_pin_nids[14] = {
353 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
354 0x0f, 0x10, 0x11, 0x12, 0x13,
355 0x14, 0x21, 0x22, 0x23,
356};
357
Matt Porterf3302a52006-07-31 12:49:34 +0200358static hda_nid_t stac9205_pin_nids[12] = {
359 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
360 0x0f, 0x14, 0x16, 0x17, 0x18,
361 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200362};
363
Matt Porter8b657272006-10-26 17:12:59 +0200364static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
365 struct snd_ctl_elem_info *uinfo)
366{
367 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
368 struct sigmatel_spec *spec = codec->spec;
369 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
370}
371
372static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
373 struct snd_ctl_elem_value *ucontrol)
374{
375 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
376 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100377 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200378
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100379 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200380 return 0;
381}
382
383static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
384 struct snd_ctl_elem_value *ucontrol)
385{
386 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
387 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100388 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200389
390 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100391 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200392}
393
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100394static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200395{
396 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
397 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200398 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200399}
400
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100401static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200402{
403 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
404 struct sigmatel_spec *spec = codec->spec;
405 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
406
407 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
408 return 0;
409}
410
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100411static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200412{
413 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
414 struct sigmatel_spec *spec = codec->spec;
415 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
416
Mattc7d4b2f2005-06-27 14:59:41 +0200417 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200418 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
419}
420
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100421static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
422 struct snd_ctl_elem_info *uinfo)
423{
424 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
425 struct sigmatel_spec *spec = codec->spec;
426 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
427}
428
429static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
430 struct snd_ctl_elem_value *ucontrol)
431{
432 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
433 struct sigmatel_spec *spec = codec->spec;
434
435 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
436 return 0;
437}
438
439static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
440 struct snd_ctl_elem_value *ucontrol)
441{
442 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
443 struct sigmatel_spec *spec = codec->spec;
444
445 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
446 spec->mono_nid, &spec->cur_mmux);
447}
448
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200449#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
450
451static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_value *ucontrol)
453{
454 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100455 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200456 struct sigmatel_spec *spec = codec->spec;
457
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100458 ucontrol->value.integer.value[0] = !!(spec->aloopback &
459 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200460 return 0;
461}
462
463static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
464 struct snd_ctl_elem_value *ucontrol)
465{
466 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
467 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100468 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200469 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100470 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200471
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100472 idx_val = spec->aloopback_mask << idx;
473 if (ucontrol->value.integer.value[0])
474 val = spec->aloopback | idx_val;
475 else
476 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100477 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200478 return 0;
479
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100480 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200481
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100482 /* Only return the bits defined by the shift value of the
483 * first two bytes of the mask
484 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200485 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100486 kcontrol->private_value & 0xFFFF, 0x0);
487 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200488
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100489 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200490 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100491 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200492 } else {
493 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100494 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200495 }
496
497 snd_hda_codec_write_cache(codec, codec->afg, 0,
498 kcontrol->private_value >> 16, dac_mode);
499
500 return 1;
501}
502
Mattc7d4b2f2005-06-27 14:59:41 +0200503static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200504 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200505 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200506 {}
507};
508
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200509static struct hda_verb stac9200_eapd_init[] = {
510 /* set dac0mux for dac converter */
511 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
512 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
513 {}
514};
515
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100516static struct hda_verb stac92hd73xx_6ch_core_init[] = {
517 /* set master volume and direct control */
518 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
519 /* setup audio connections */
520 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
521 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
522 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
523 /* setup adcs to point to mixer */
524 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
525 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100526 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
527 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
528 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
529 /* setup import muxs */
530 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
531 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
532 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
533 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
534 {}
535};
536
Matthew Ranostayd654a662008-03-14 08:46:51 +0100537static struct hda_verb dell_eq_core_init[] = {
538 /* set master volume to max value without distortion
539 * and direct control */
540 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
541 /* setup audio connections */
542 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
543 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
544 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
545 /* setup adcs to point to mixer */
546 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
547 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
548 /* setup import muxs */
549 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
550 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
551 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
552 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
553 {}
554};
555
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100556static struct hda_verb dell_m6_core_init[] = {
557 /* set master volume and direct control */
558 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
559 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100560 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
561 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100562 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
563 /* setup adcs to point to mixer */
564 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
565 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
566 /* setup import muxs */
567 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
568 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
569 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
570 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
571 {}
572};
573
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100574static struct hda_verb stac92hd73xx_8ch_core_init[] = {
575 /* set master volume and direct control */
576 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
577 /* setup audio connections */
578 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
579 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
580 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
581 /* connect hp ports to dac3 */
582 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
583 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
584 /* setup adcs to point to mixer */
585 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
586 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100587 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
588 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
589 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
590 /* setup import muxs */
591 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
592 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
593 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
594 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
595 {}
596};
597
598static struct hda_verb stac92hd73xx_10ch_core_init[] = {
599 /* set master volume and direct control */
600 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
601 /* setup audio connections */
602 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
603 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
604 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
605 /* dac3 is connected to import3 mux */
606 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
607 /* connect hp ports to dac4 */
608 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
609 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
610 /* setup adcs to point to mixer */
611 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
612 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100613 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
614 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
615 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
616 /* setup import muxs */
617 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
618 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
619 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
620 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
621 {}
622};
623
Matthew Ranostaye035b842007-11-06 11:53:55 +0100624static struct hda_verb stac92hd71bxx_core_init[] = {
625 /* set master volume and direct control */
626 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
627 /* connect headphone jack to dac1 */
628 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100629 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
630 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
631 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
632 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
633 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100634};
635
636static struct hda_verb stac92hd71bxx_analog_core_init[] = {
637 /* set master volume and direct control */
638 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
639 /* connect headphone jack to dac1 */
640 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100641 /* connect ports 0d and 0f to audio mixer */
642 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
643 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100644 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100645 /* unmute dac0 input in audio mixer */
646 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100647 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
648 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
649 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
650 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100651 {}
652};
653
Tobin Davis8e21c342007-01-08 11:04:17 +0100654static struct hda_verb stac925x_core_init[] = {
655 /* set dac0mux for dac converter */
656 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
657 {}
658};
659
Mattc7d4b2f2005-06-27 14:59:41 +0200660static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200661 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200662 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200663 {}
664};
665
Tobin Davis93ed1502006-09-01 21:03:12 +0200666static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200667 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200668 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200669 /* unmute node 0x1b */
670 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
671 /* select node 0x03 as DAC */
672 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
673 {}
674};
675
Matt Porter3cc08dc2006-01-23 15:27:49 +0100676static struct hda_verb stac927x_core_init[] = {
677 /* set master volume and direct control */
678 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
679 {}
680};
681
Matt Porterf3302a52006-07-31 12:49:34 +0200682static struct hda_verb stac9205_core_init[] = {
683 /* set master volume and direct control */
684 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
685 {}
686};
687
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100688#define STAC_MONO_MUX \
689 { \
690 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
691 .name = "Mono Mux", \
692 .count = 1, \
693 .info = stac92xx_mono_mux_enum_info, \
694 .get = stac92xx_mono_mux_enum_get, \
695 .put = stac92xx_mono_mux_enum_put, \
696 }
697
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200698#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200699 { \
700 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
701 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200702 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200703 .info = stac92xx_mux_enum_info, \
704 .get = stac92xx_mux_enum_get, \
705 .put = stac92xx_mux_enum_put, \
706 }
707
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100708#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200709 { \
710 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
711 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100712 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200713 .info = stac92xx_aloopback_info, \
714 .get = stac92xx_aloopback_get, \
715 .put = stac92xx_aloopback_put, \
716 .private_value = verb_read | (verb_write << 16), \
717 }
718
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100719static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200720 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
721 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200722 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200723 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
724 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200725 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200726 { } /* end */
727};
728
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100729static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100730 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
731
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
733 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
734
735 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
736 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
737
738 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
739 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
740
741 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
742 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
743
744 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
745 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
746
747 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
748 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
749
750 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
751 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
752 { } /* end */
753};
754
755static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100756 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
757
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100758 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
759 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
760
761 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
762 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
763
764 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
765 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
766
767 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
768 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
769
770 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
771 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
772
773 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
774 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
775
776 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
777 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
778 { } /* end */
779};
780
781static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100782 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
783
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100784 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
785 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
786
787 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
788 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
789
790 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
791 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
792
793 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
794 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
795
796 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
797 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
798
799 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
800 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
801
802 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
803 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
804 { } /* end */
805};
806
Matthew Ranostay541eee82007-12-14 12:08:04 +0100807static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100808 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100809
Matthew Ranostay9b359472007-11-07 13:03:12 +0100810 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
811 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
812 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
813
814 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
815 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
816 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
817
818 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
819 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100820 { } /* end */
821};
822
Matthew Ranostay541eee82007-12-14 12:08:04 +0100823static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100824 STAC_INPUT_SOURCE(2),
825 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
826
Matthew Ranostay541eee82007-12-14 12:08:04 +0100827 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
828 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
829 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
830
831 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
832 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
833 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
834 { } /* end */
835};
836
Tobin Davis8e21c342007-01-08 11:04:17 +0100837static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200838 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100839 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
840 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
841 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
842 { } /* end */
843};
844
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100845static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200846 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100847 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200848
849 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
850 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
851 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
852
853 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
854 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
855 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
856
857 { } /* end */
858};
859
860/* This needs to be generated dynamically based on sequence */
861static struct snd_kcontrol_new stac922x_mixer[] = {
862 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200863 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
864 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
865 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
866
867 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
868 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
869 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
870 { } /* end */
871};
872
873
874static struct snd_kcontrol_new stac927x_mixer[] = {
875 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100876 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200877
878 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
879 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
880 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
881
882 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
883 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
884 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
885
886 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
887 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
888 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200889 { } /* end */
890};
891
Takashi Iwai1697055e2007-12-18 18:05:52 +0100892static struct snd_kcontrol_new stac_dmux_mixer = {
893 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
894 .name = "Digital Input Source",
895 /* count set later */
896 .info = stac92xx_dmux_enum_info,
897 .get = stac92xx_dmux_enum_get,
898 .put = stac92xx_dmux_enum_put,
899};
900
Takashi Iwai2134ea42008-01-10 16:53:55 +0100901static const char *slave_vols[] = {
902 "Front Playback Volume",
903 "Surround Playback Volume",
904 "Center Playback Volume",
905 "LFE Playback Volume",
906 "Side Playback Volume",
907 "Headphone Playback Volume",
908 "Headphone Playback Volume",
909 "Speaker Playback Volume",
910 "External Speaker Playback Volume",
911 "Speaker2 Playback Volume",
912 NULL
913};
914
915static const char *slave_sws[] = {
916 "Front Playback Switch",
917 "Surround Playback Switch",
918 "Center Playback Switch",
919 "LFE Playback Switch",
920 "Side Playback Switch",
921 "Headphone Playback Switch",
922 "Headphone Playback Switch",
923 "Speaker Playback Switch",
924 "External Speaker Playback Switch",
925 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100926 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100927 NULL
928};
929
Matt2f2f4252005-04-13 14:45:30 +0200930static int stac92xx_build_controls(struct hda_codec *codec)
931{
932 struct sigmatel_spec *spec = codec->spec;
933 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200934 int i;
Matt2f2f4252005-04-13 14:45:30 +0200935
936 err = snd_hda_add_new_ctls(codec, spec->mixer);
937 if (err < 0)
938 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200939
940 for (i = 0; i < spec->num_mixers; i++) {
941 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
942 if (err < 0)
943 return err;
944 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100945 if (spec->num_dmuxes > 0) {
946 stac_dmux_mixer.count = spec->num_dmuxes;
947 err = snd_ctl_add(codec->bus->card,
948 snd_ctl_new1(&stac_dmux_mixer, codec));
949 if (err < 0)
950 return err;
951 }
Mattc7d4b2f2005-06-27 14:59:41 +0200952
Mattdabbed62005-06-14 10:19:34 +0200953 if (spec->multiout.dig_out_nid) {
954 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
955 if (err < 0)
956 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100957 err = snd_hda_create_spdif_share_sw(codec,
958 &spec->multiout);
959 if (err < 0)
960 return err;
961 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200962 }
963 if (spec->dig_in_nid) {
964 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
965 if (err < 0)
966 return err;
967 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100968
969 /* if we have no master control, let's create it */
970 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100971 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100972 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100973 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100974 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100975 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100976 if (err < 0)
977 return err;
978 }
979 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
980 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
981 NULL, slave_sws);
982 if (err < 0)
983 return err;
984 }
985
Mattdabbed62005-06-14 10:19:34 +0200986 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200987}
988
Matt Porter403d1942005-11-29 15:00:51 +0100989static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200990 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200991 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
992};
993
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200994/*
995 STAC 9200 pin configs for
996 102801A8
997 102801DE
998 102801E8
999*/
1000static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001001 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1002 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001003};
1004
1005/*
1006 STAC 9200 pin configs for
1007 102801C0
1008 102801C1
1009*/
1010static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001011 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1012 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001013};
1014
1015/*
1016 STAC 9200 pin configs for
1017 102801C4 (Dell Dimension E310)
1018 102801C5
1019 102801C7
1020 102801D9
1021 102801DA
1022 102801E3
1023*/
1024static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001025 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1026 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001027};
1028
1029
1030/*
1031 STAC 9200-32 pin configs for
1032 102801B5 (Dell Inspiron 630m)
1033 102801D8 (Dell Inspiron 640m)
1034*/
1035static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001036 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1037 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001038};
1039
1040/*
1041 STAC 9200-32 pin configs for
1042 102801C2 (Dell Latitude D620)
1043 102801C8
1044 102801CC (Dell Latitude D820)
1045 102801D4
1046 102801D6
1047*/
1048static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001049 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1050 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001051};
1052
1053/*
1054 STAC 9200-32 pin configs for
1055 102801CE (Dell XPS M1710)
1056 102801CF (Dell Precision M90)
1057*/
1058static unsigned int dell9200_m23_pin_configs[8] = {
1059 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1060 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1061};
1062
1063/*
1064 STAC 9200-32 pin configs for
1065 102801C9
1066 102801CA
1067 102801CB (Dell Latitude 120L)
1068 102801D3
1069*/
1070static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001071 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1072 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001073};
1074
1075/*
1076 STAC 9200-32 pin configs for
1077 102801BD (Dell Inspiron E1505n)
1078 102801EE
1079 102801EF
1080*/
1081static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001082 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1083 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001084};
1085
1086/*
1087 STAC 9200-32 pin configs for
1088 102801F5 (Dell Inspiron 1501)
1089 102801F6
1090*/
1091static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001092 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1093 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001094};
1095
1096/*
1097 STAC 9200-32
1098 102801CD (Dell Inspiron E1705/9400)
1099*/
1100static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001101 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1102 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001103};
1104
Tobin Davisbf277782008-02-03 20:31:47 +01001105static unsigned int oqo9200_pin_configs[8] = {
1106 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1107 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1108};
1109
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001110
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001111static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1112 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001113 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001114 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1115 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1116 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1117 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1118 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1119 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1120 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1121 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1122 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1123 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001124};
1125
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001126static const char *stac9200_models[STAC_9200_MODELS] = {
1127 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001128 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001129 [STAC_9200_DELL_D21] = "dell-d21",
1130 [STAC_9200_DELL_D22] = "dell-d22",
1131 [STAC_9200_DELL_D23] = "dell-d23",
1132 [STAC_9200_DELL_M21] = "dell-m21",
1133 [STAC_9200_DELL_M22] = "dell-m22",
1134 [STAC_9200_DELL_M23] = "dell-m23",
1135 [STAC_9200_DELL_M24] = "dell-m24",
1136 [STAC_9200_DELL_M25] = "dell-m25",
1137 [STAC_9200_DELL_M26] = "dell-m26",
1138 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001139 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001140};
1141
1142static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1143 /* SigmaTel reference board */
1144 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1145 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001146 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001147 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1148 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001149 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001150 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1151 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1152 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1153 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1154 "unknown Dell", STAC_9200_DELL_D22),
1155 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1156 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001157 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001158 "Dell Latitude D620", STAC_9200_DELL_M22),
1159 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1160 "unknown Dell", STAC_9200_DELL_D23),
1161 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1162 "unknown Dell", STAC_9200_DELL_D23),
1163 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1164 "unknown Dell", STAC_9200_DELL_M22),
1165 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1166 "unknown Dell", STAC_9200_DELL_M24),
1167 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1168 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001169 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001170 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001171 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001172 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001173 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001174 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001175 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001176 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001177 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001178 "Dell Precision M90", STAC_9200_DELL_M23),
1179 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1180 "unknown Dell", STAC_9200_DELL_M22),
1181 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1182 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001183 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001184 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001185 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001186 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1187 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1188 "unknown Dell", STAC_9200_DELL_D23),
1189 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1190 "unknown Dell", STAC_9200_DELL_D23),
1191 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1192 "unknown Dell", STAC_9200_DELL_D21),
1193 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1194 "unknown Dell", STAC_9200_DELL_D23),
1195 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1196 "unknown Dell", STAC_9200_DELL_D21),
1197 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1198 "unknown Dell", STAC_9200_DELL_M25),
1199 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1200 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001201 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001202 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1203 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1204 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001205 /* Panasonic */
1206 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001207 /* Gateway machines needs EAPD to be set on resume */
1208 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1209 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1210 STAC_9200_GATEWAY),
1211 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1212 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001213 /* OQO Mobile */
1214 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001215 {} /* terminator */
1216};
1217
Tobin Davis8e21c342007-01-08 11:04:17 +01001218static unsigned int ref925x_pin_configs[8] = {
1219 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001220 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001221};
1222
1223static unsigned int stac925x_MA6_pin_configs[8] = {
1224 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1225 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1226};
1227
Tobin Davis2c11f952007-05-17 09:36:34 +02001228static unsigned int stac925x_PA6_pin_configs[8] = {
1229 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1230 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1231};
1232
Tobin Davis8e21c342007-01-08 11:04:17 +01001233static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001234 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1235 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001236};
1237
1238static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1239 [STAC_REF] = ref925x_pin_configs,
1240 [STAC_M2_2] = stac925xM2_2_pin_configs,
1241 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001242 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001243};
1244
1245static const char *stac925x_models[STAC_925x_MODELS] = {
1246 [STAC_REF] = "ref",
1247 [STAC_M2_2] = "m2-2",
1248 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001249 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001250};
1251
1252static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1253 /* SigmaTel reference board */
1254 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001255 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001256 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1257 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1258 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001259 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001260 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1261 {} /* terminator */
1262};
1263
Matthew Ranostaya7662642008-02-21 07:51:14 +01001264static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001265 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1266 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1267 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001268 0x01452050,
1269};
1270
1271static unsigned int dell_m6_pin_configs[13] = {
1272 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
1273 0x03a11020, 0x03011050, 0x4f0000f0, 0x4f0000f0,
1274 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1275 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001276};
1277
1278static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001279 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1280 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001281};
1282
1283static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1284 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001285 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001286};
1287
1288static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1289 /* SigmaTel reference board */
1290 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001291 "DFI LanParty", STAC_92HD73XX_REF),
1292 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1293 "unknown Dell", STAC_DELL_M6),
1294 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1295 "unknown Dell", STAC_DELL_M6),
1296 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1297 "unknown Dell", STAC_DELL_M6),
1298 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1299 "unknown Dell", STAC_DELL_M6),
1300 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1301 "unknown Dell", STAC_DELL_M6),
1302 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1303 "unknown Dell", STAC_DELL_M6),
1304 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1305 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001306 {} /* terminator */
1307};
1308
Matthew Ranostaye035b842007-11-06 11:53:55 +01001309static unsigned int ref92hd71bxx_pin_configs[10] = {
1310 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001311 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001312 0x90a000f0, 0x01452050,
1313};
1314
Matthew Ranostaya7662642008-02-21 07:51:14 +01001315static unsigned int dell_m4_1_pin_configs[13] = {
1316 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
1317 0x23a1902e, 0x23014250, 0x40f000f0, 0x4f0000f0,
1318 0x40f000f0, 0x4f0000f0,
1319};
1320
1321static unsigned int dell_m4_2_pin_configs[13] = {
1322 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1323 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1324 0x40f000f0, 0x044413b0,
1325};
1326
Matthew Ranostaye035b842007-11-06 11:53:55 +01001327static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1328 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001329 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1330 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001331};
1332
1333static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1334 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001335 [STAC_DELL_M4_1] = "dell-m4-1",
1336 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001337};
1338
1339static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1340 /* SigmaTel reference board */
1341 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1342 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001343 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1344 "unknown Dell", STAC_DELL_M4_1),
1345 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1346 "unknown Dell", STAC_DELL_M4_1),
1347 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1348 "unknown Dell", STAC_DELL_M4_1),
1349 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1350 "unknown Dell", STAC_DELL_M4_1),
1351 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1352 "unknown Dell", STAC_DELL_M4_1),
1353 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1354 "unknown Dell", STAC_DELL_M4_1),
1355 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1356 "unknown Dell", STAC_DELL_M4_1),
1357 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1358 "unknown Dell", STAC_DELL_M4_2),
1359 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1360 "unknown Dell", STAC_DELL_M4_2),
1361 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1362 "unknown Dell", STAC_DELL_M4_2),
1363 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1364 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001365 {} /* terminator */
1366};
1367
Matt Porter403d1942005-11-29 15:00:51 +01001368static unsigned int ref922x_pin_configs[10] = {
1369 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1370 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001371 0x40000100, 0x40000100,
1372};
1373
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001374/*
1375 STAC 922X pin configs for
1376 102801A7
1377 102801AB
1378 102801A9
1379 102801D1
1380 102801D2
1381*/
1382static unsigned int dell_922x_d81_pin_configs[10] = {
1383 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1384 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1385 0x01813122, 0x400001f2,
1386};
1387
1388/*
1389 STAC 922X pin configs for
1390 102801AC
1391 102801D0
1392*/
1393static unsigned int dell_922x_d82_pin_configs[10] = {
1394 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1395 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1396 0x01813122, 0x400001f1,
1397};
1398
1399/*
1400 STAC 922X pin configs for
1401 102801BF
1402*/
1403static unsigned int dell_922x_m81_pin_configs[10] = {
1404 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1405 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1406 0x40C003f1, 0x405003f0,
1407};
1408
1409/*
1410 STAC 9221 A1 pin configs for
1411 102801D7 (Dell XPS M1210)
1412*/
1413static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001414 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1415 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001416 0x508003f3, 0x405003f4,
1417};
1418
Matt Porter403d1942005-11-29 15:00:51 +01001419static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001420 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001421 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1422 0x02a19120, 0x40000100,
1423};
1424
1425static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001426 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1427 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001428 0x02a19320, 0x40000100,
1429};
1430
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001431static unsigned int intel_mac_v1_pin_configs[10] = {
1432 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1433 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001434 0x400000fc, 0x400000fb,
1435};
1436
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001437static unsigned int intel_mac_v2_pin_configs[10] = {
1438 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1439 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001440 0x400000fc, 0x400000fb,
1441};
1442
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001443static unsigned int intel_mac_v3_pin_configs[10] = {
1444 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1445 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1446 0x400000fc, 0x400000fb,
1447};
1448
1449static unsigned int intel_mac_v4_pin_configs[10] = {
1450 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1451 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1452 0x400000fc, 0x400000fb,
1453};
1454
1455static unsigned int intel_mac_v5_pin_configs[10] = {
1456 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1457 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1458 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001459};
1460
Takashi Iwai76c08822007-06-19 12:17:42 +02001461
Takashi Iwai19039bd2006-06-28 15:52:16 +02001462static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001463 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001464 [STAC_D945GTP3] = d945gtp3_pin_configs,
1465 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001466 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1467 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1468 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1469 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1470 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001471 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001472 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1473 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1474 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1475 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1476 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1477 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001478 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1479 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1480 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1481 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001482};
1483
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001484static const char *stac922x_models[STAC_922X_MODELS] = {
1485 [STAC_D945_REF] = "ref",
1486 [STAC_D945GTP5] = "5stack",
1487 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001488 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1489 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1490 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1491 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1492 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001493 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001494 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001495 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001496 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1497 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001498 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001499 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001500 [STAC_922X_DELL_D81] = "dell-d81",
1501 [STAC_922X_DELL_D82] = "dell-d82",
1502 [STAC_922X_DELL_M81] = "dell-m81",
1503 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001504};
1505
1506static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1507 /* SigmaTel reference board */
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1509 "DFI LanParty", STAC_D945_REF),
1510 /* Intel 945G based systems */
1511 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1512 "Intel D945G", STAC_D945GTP3),
1513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1514 "Intel D945G", STAC_D945GTP3),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1516 "Intel D945G", STAC_D945GTP3),
1517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1518 "Intel D945G", STAC_D945GTP3),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1520 "Intel D945G", STAC_D945GTP3),
1521 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1522 "Intel D945G", STAC_D945GTP3),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1524 "Intel D945G", STAC_D945GTP3),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1526 "Intel D945G", STAC_D945GTP3),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1528 "Intel D945G", STAC_D945GTP3),
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1530 "Intel D945G", STAC_D945GTP3),
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1532 "Intel D945G", STAC_D945GTP3),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1534 "Intel D945G", STAC_D945GTP3),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1536 "Intel D945G", STAC_D945GTP3),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1538 "Intel D945G", STAC_D945GTP3),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1540 "Intel D945G", STAC_D945GTP3),
1541 /* Intel D945G 5-stack systems */
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1543 "Intel D945G", STAC_D945GTP5),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1545 "Intel D945G", STAC_D945GTP5),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1547 "Intel D945G", STAC_D945GTP5),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1549 "Intel D945G", STAC_D945GTP5),
1550 /* Intel 945P based systems */
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1552 "Intel D945P", STAC_D945GTP3),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1554 "Intel D945P", STAC_D945GTP3),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1556 "Intel D945P", STAC_D945GTP3),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1558 "Intel D945P", STAC_D945GTP3),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1560 "Intel D945P", STAC_D945GTP3),
1561 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1562 "Intel D945P", STAC_D945GTP5),
1563 /* other systems */
1564 /* Apple Mac Mini (early 2006) */
1565 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001566 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001567 /* Dell systems */
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1569 "unknown Dell", STAC_922X_DELL_D81),
1570 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1571 "unknown Dell", STAC_922X_DELL_D81),
1572 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1573 "unknown Dell", STAC_922X_DELL_D81),
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1575 "unknown Dell", STAC_922X_DELL_D82),
1576 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1577 "unknown Dell", STAC_922X_DELL_M81),
1578 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1579 "unknown Dell", STAC_922X_DELL_D82),
1580 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1581 "unknown Dell", STAC_922X_DELL_D81),
1582 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1583 "unknown Dell", STAC_922X_DELL_D81),
1584 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1585 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001586 {} /* terminator */
1587};
1588
Matt Porter3cc08dc2006-01-23 15:27:49 +01001589static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001590 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1591 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1592 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1593 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001594};
1595
Tobin Davis93ed1502006-09-01 21:03:12 +02001596static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001597 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1598 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1599 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1600 0x40000100, 0x40000100
1601};
1602
Tobin Davis93ed1502006-09-01 21:03:12 +02001603static unsigned int d965_5st_pin_configs[14] = {
1604 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1605 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1606 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1607 0x40000100, 0x40000100
1608};
1609
Tobin Davis4ff076e2007-08-07 11:48:12 +02001610static unsigned int dell_3st_pin_configs[14] = {
1611 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1612 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001613 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001614 0x40c003fc, 0x40000100
1615};
1616
Tobin Davis93ed1502006-09-01 21:03:12 +02001617static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001618 [STAC_D965_REF] = ref927x_pin_configs,
1619 [STAC_D965_3ST] = d965_3st_pin_configs,
1620 [STAC_D965_5ST] = d965_5st_pin_configs,
1621 [STAC_DELL_3ST] = dell_3st_pin_configs,
1622 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001623};
1624
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001625static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001626 [STAC_D965_REF] = "ref",
1627 [STAC_D965_3ST] = "3stack",
1628 [STAC_D965_5ST] = "5stack",
1629 [STAC_DELL_3ST] = "dell-3stack",
1630 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001631};
1632
1633static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1634 /* SigmaTel reference board */
1635 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1636 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001637 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001638 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1639 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001640 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001641 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1643 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1644 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1645 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1646 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1648 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1649 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1650 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1652 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1653 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1654 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1656 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001657 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001658 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001659 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001660 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1661 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001662 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001663 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1664 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001665 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1666 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1667 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1668 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1669 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1670 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001671 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001672 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1674 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1675 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1676 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1677 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1678 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1679 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1680 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001681 {} /* terminator */
1682};
1683
Matt Porterf3302a52006-07-31 12:49:34 +02001684static unsigned int ref9205_pin_configs[12] = {
1685 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001686 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001687 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001688};
1689
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001690/*
1691 STAC 9205 pin configs for
1692 102801F1
1693 102801F2
1694 102801FC
1695 102801FD
1696 10280204
1697 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001698 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001699*/
1700static unsigned int dell_9205_m42_pin_configs[12] = {
1701 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1702 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1703 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1704};
1705
1706/*
1707 STAC 9205 pin configs for
1708 102801F9
1709 102801FA
1710 102801FE
1711 102801FF (Dell Precision M4300)
1712 10280206
1713 10280200
1714 10280201
1715*/
1716static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001717 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1718 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1719 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1720};
1721
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001722static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001723 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1724 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1725 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1726};
1727
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001728static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001729 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001730 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1731 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1732 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001733};
1734
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001735static const char *stac9205_models[STAC_9205_MODELS] = {
1736 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001737 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001738 [STAC_9205_DELL_M43] = "dell-m43",
1739 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001740};
1741
1742static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1743 /* SigmaTel reference board */
1744 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1745 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001746 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1747 "unknown Dell", STAC_9205_DELL_M42),
1748 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1749 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001750 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001751 "Dell Precision", STAC_9205_DELL_M43),
1752 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1753 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001754 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1755 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001756 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1757 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001758 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1759 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001760 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1761 "unknown Dell", STAC_9205_DELL_M42),
1762 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1763 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001764 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1765 "Dell Precision", STAC_9205_DELL_M43),
1766 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001767 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001768 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1769 "Dell Precision", STAC_9205_DELL_M43),
1770 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1771 "Dell Inspiron", STAC_9205_DELL_M44),
1772 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1773 "Dell Inspiron", STAC_9205_DELL_M44),
1774 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1775 "Dell Inspiron", STAC_9205_DELL_M44),
1776 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1777 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001778 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1779 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001780 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1781 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001782 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1783 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001784 {} /* terminator */
1785};
1786
Richard Fish11b44bb2006-08-23 18:31:34 +02001787static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1788{
1789 int i;
1790 struct sigmatel_spec *spec = codec->spec;
1791
1792 if (! spec->bios_pin_configs) {
1793 spec->bios_pin_configs = kcalloc(spec->num_pins,
1794 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1795 if (! spec->bios_pin_configs)
1796 return -ENOMEM;
1797 }
1798
1799 for (i = 0; i < spec->num_pins; i++) {
1800 hda_nid_t nid = spec->pin_nids[i];
1801 unsigned int pin_cfg;
1802
1803 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1804 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1805 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1806 nid, pin_cfg);
1807 spec->bios_pin_configs[i] = pin_cfg;
1808 }
1809
1810 return 0;
1811}
1812
Matthew Ranostay87d48362007-07-17 11:52:24 +02001813static void stac92xx_set_config_reg(struct hda_codec *codec,
1814 hda_nid_t pin_nid, unsigned int pin_config)
1815{
1816 int i;
1817 snd_hda_codec_write(codec, pin_nid, 0,
1818 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1819 pin_config & 0x000000ff);
1820 snd_hda_codec_write(codec, pin_nid, 0,
1821 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1822 (pin_config & 0x0000ff00) >> 8);
1823 snd_hda_codec_write(codec, pin_nid, 0,
1824 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1825 (pin_config & 0x00ff0000) >> 16);
1826 snd_hda_codec_write(codec, pin_nid, 0,
1827 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1828 pin_config >> 24);
1829 i = snd_hda_codec_read(codec, pin_nid, 0,
1830 AC_VERB_GET_CONFIG_DEFAULT,
1831 0x00);
1832 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1833 pin_nid, i);
1834}
1835
Matt2f2f4252005-04-13 14:45:30 +02001836static void stac92xx_set_config_regs(struct hda_codec *codec)
1837{
1838 int i;
1839 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001840
Matthew Ranostay87d48362007-07-17 11:52:24 +02001841 if (!spec->pin_configs)
1842 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001843
Matthew Ranostay87d48362007-07-17 11:52:24 +02001844 for (i = 0; i < spec->num_pins; i++)
1845 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1846 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001847}
Matt2f2f4252005-04-13 14:45:30 +02001848
Matt2f2f4252005-04-13 14:45:30 +02001849/*
1850 * Analog playback callbacks
1851 */
1852static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1853 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001854 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001855{
1856 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001857 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1858 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001859}
1860
1861static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1862 struct hda_codec *codec,
1863 unsigned int stream_tag,
1864 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001865 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001866{
1867 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001868 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001869}
1870
1871static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1872 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001873 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001874{
1875 struct sigmatel_spec *spec = codec->spec;
1876 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1877}
1878
1879/*
Mattdabbed62005-06-14 10:19:34 +02001880 * Digital playback callbacks
1881 */
1882static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1883 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001884 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001885{
1886 struct sigmatel_spec *spec = codec->spec;
1887 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1888}
1889
1890static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1891 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001892 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001893{
1894 struct sigmatel_spec *spec = codec->spec;
1895 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1896}
1897
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001898static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1899 struct hda_codec *codec,
1900 unsigned int stream_tag,
1901 unsigned int format,
1902 struct snd_pcm_substream *substream)
1903{
1904 struct sigmatel_spec *spec = codec->spec;
1905 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1906 stream_tag, format, substream);
1907}
1908
Mattdabbed62005-06-14 10:19:34 +02001909
1910/*
Matt2f2f4252005-04-13 14:45:30 +02001911 * Analog capture callbacks
1912 */
1913static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1914 struct hda_codec *codec,
1915 unsigned int stream_tag,
1916 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001917 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001918{
1919 struct sigmatel_spec *spec = codec->spec;
1920
1921 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1922 stream_tag, 0, format);
1923 return 0;
1924}
1925
1926static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1927 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001928 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001929{
1930 struct sigmatel_spec *spec = codec->spec;
1931
1932 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1933 return 0;
1934}
1935
Mattdabbed62005-06-14 10:19:34 +02001936static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1937 .substreams = 1,
1938 .channels_min = 2,
1939 .channels_max = 2,
1940 /* NID is set in stac92xx_build_pcms */
1941 .ops = {
1942 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001943 .close = stac92xx_dig_playback_pcm_close,
1944 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001945 },
1946};
1947
1948static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1949 .substreams = 1,
1950 .channels_min = 2,
1951 .channels_max = 2,
1952 /* NID is set in stac92xx_build_pcms */
1953};
1954
Matt2f2f4252005-04-13 14:45:30 +02001955static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1956 .substreams = 1,
1957 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001958 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001959 .nid = 0x02, /* NID to query formats and rates */
1960 .ops = {
1961 .open = stac92xx_playback_pcm_open,
1962 .prepare = stac92xx_playback_pcm_prepare,
1963 .cleanup = stac92xx_playback_pcm_cleanup
1964 },
1965};
1966
Matt Porter3cc08dc2006-01-23 15:27:49 +01001967static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1968 .substreams = 1,
1969 .channels_min = 2,
1970 .channels_max = 2,
1971 .nid = 0x06, /* NID to query formats and rates */
1972 .ops = {
1973 .open = stac92xx_playback_pcm_open,
1974 .prepare = stac92xx_playback_pcm_prepare,
1975 .cleanup = stac92xx_playback_pcm_cleanup
1976 },
1977};
1978
Matt2f2f4252005-04-13 14:45:30 +02001979static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001980 .channels_min = 2,
1981 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001982 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001983 .ops = {
1984 .prepare = stac92xx_capture_pcm_prepare,
1985 .cleanup = stac92xx_capture_pcm_cleanup
1986 },
1987};
1988
1989static int stac92xx_build_pcms(struct hda_codec *codec)
1990{
1991 struct sigmatel_spec *spec = codec->spec;
1992 struct hda_pcm *info = spec->pcm_rec;
1993
1994 codec->num_pcms = 1;
1995 codec->pcm_info = info;
1996
Mattc7d4b2f2005-06-27 14:59:41 +02001997 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001998 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001999 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002000 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002001 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002002
2003 if (spec->alt_switch) {
2004 codec->num_pcms++;
2005 info++;
2006 info->name = "STAC92xx Analog Alt";
2007 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2008 }
Matt2f2f4252005-04-13 14:45:30 +02002009
Mattdabbed62005-06-14 10:19:34 +02002010 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2011 codec->num_pcms++;
2012 info++;
2013 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002014 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002015 if (spec->multiout.dig_out_nid) {
2016 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2017 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2018 }
2019 if (spec->dig_in_nid) {
2020 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2021 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2022 }
2023 }
2024
Matt2f2f4252005-04-13 14:45:30 +02002025 return 0;
2026}
2027
Takashi Iwaic960a032006-03-23 17:06:28 +01002028static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2029{
2030 unsigned int pincap = snd_hda_param_read(codec, nid,
2031 AC_PAR_PIN_CAP);
2032 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2033 if (pincap & AC_PINCAP_VREF_100)
2034 return AC_PINCTL_VREF_100;
2035 if (pincap & AC_PINCAP_VREF_80)
2036 return AC_PINCTL_VREF_80;
2037 if (pincap & AC_PINCAP_VREF_50)
2038 return AC_PINCTL_VREF_50;
2039 if (pincap & AC_PINCAP_VREF_GRD)
2040 return AC_PINCTL_VREF_GRD;
2041 return 0;
2042}
2043
Matt Porter403d1942005-11-29 15:00:51 +01002044static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2045
2046{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002047 snd_hda_codec_write_cache(codec, nid, 0,
2048 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002049}
2050
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002051#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002052
2053static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2054{
2055 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2056 struct sigmatel_spec *spec = codec->spec;
2057 int io_idx = kcontrol-> private_value & 0xff;
2058
2059 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2060 return 0;
2061}
2062
2063static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2064{
2065 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2066 struct sigmatel_spec *spec = codec->spec;
2067 hda_nid_t nid = kcontrol->private_value >> 8;
2068 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002069 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002070
2071 spec->io_switch[io_idx] = val;
2072
2073 if (val)
2074 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002075 else {
2076 unsigned int pinctl = AC_PINCTL_IN_EN;
2077 if (io_idx) /* set VREF for mic */
2078 pinctl |= stac92xx_get_vref(codec, nid);
2079 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2080 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002081
2082 /* check the auto-mute again: we need to mute/unmute the speaker
2083 * appropriately according to the pin direction
2084 */
2085 if (spec->hp_detect)
2086 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2087
Matt Porter403d1942005-11-29 15:00:51 +01002088 return 1;
2089}
2090
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002091#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2092
2093static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2094 struct snd_ctl_elem_value *ucontrol)
2095{
2096 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2097 struct sigmatel_spec *spec = codec->spec;
2098
2099 ucontrol->value.integer.value[0] = spec->clfe_swap;
2100 return 0;
2101}
2102
2103static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2104 struct snd_ctl_elem_value *ucontrol)
2105{
2106 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2107 struct sigmatel_spec *spec = codec->spec;
2108 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002109 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002110
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002111 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002112 return 0;
2113
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002114 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002115
2116 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2117 spec->clfe_swap ? 0x4 : 0x0);
2118
2119 return 1;
2120}
2121
Matt Porter403d1942005-11-29 15:00:51 +01002122#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2123 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2124 .name = xname, \
2125 .index = 0, \
2126 .info = stac92xx_io_switch_info, \
2127 .get = stac92xx_io_switch_get, \
2128 .put = stac92xx_io_switch_put, \
2129 .private_value = xpval, \
2130 }
2131
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002132#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2133 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2134 .name = xname, \
2135 .index = 0, \
2136 .info = stac92xx_clfe_switch_info, \
2137 .get = stac92xx_clfe_switch_get, \
2138 .put = stac92xx_clfe_switch_put, \
2139 .private_value = xpval, \
2140 }
Matt Porter403d1942005-11-29 15:00:51 +01002141
Mattc7d4b2f2005-06-27 14:59:41 +02002142enum {
2143 STAC_CTL_WIDGET_VOL,
2144 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002145 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002146 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002147 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002148};
2149
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002150static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002151 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2152 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002153 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002154 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002155 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002156};
2157
2158/* add dynamic controls */
2159static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2160{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002161 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002162
2163 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2164 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2165
2166 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2167 if (! knew)
2168 return -ENOMEM;
2169 if (spec->kctl_alloc) {
2170 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2171 kfree(spec->kctl_alloc);
2172 }
2173 spec->kctl_alloc = knew;
2174 spec->num_kctl_alloc = num;
2175 }
2176
2177 knew = &spec->kctl_alloc[spec->num_kctl_used];
2178 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002179 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002180 if (! knew->name)
2181 return -ENOMEM;
2182 knew->private_value = val;
2183 spec->num_kctl_used++;
2184 return 0;
2185}
2186
Matt Porter403d1942005-11-29 15:00:51 +01002187/* flag inputs as additional dynamic lineouts */
2188static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2189{
2190 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002191 unsigned int wcaps, wtype;
2192 int i, num_dacs = 0;
2193
2194 /* use the wcaps cache to count all DACs available for line-outs */
2195 for (i = 0; i < codec->num_nodes; i++) {
2196 wcaps = codec->wcaps[i];
2197 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002198
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002199 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2200 num_dacs++;
2201 }
Matt Porter403d1942005-11-29 15:00:51 +01002202
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002203 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2204
Matt Porter403d1942005-11-29 15:00:51 +01002205 switch (cfg->line_outs) {
2206 case 3:
2207 /* add line-in as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002208 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002209 cfg->line_out_pins[cfg->line_outs] =
2210 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002211 spec->line_switch = 1;
2212 cfg->line_outs++;
2213 }
2214 break;
2215 case 2:
2216 /* add line-in as clfe and mic as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002217 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002218 cfg->line_out_pins[cfg->line_outs] =
2219 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002220 spec->line_switch = 1;
2221 cfg->line_outs++;
2222 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002223 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002224 cfg->line_out_pins[cfg->line_outs] =
2225 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002226 spec->mic_switch = 1;
2227 cfg->line_outs++;
2228 }
2229 break;
2230 case 1:
2231 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002232 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002233 cfg->line_out_pins[cfg->line_outs] =
2234 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002235 spec->line_switch = 1;
2236 cfg->line_outs++;
2237 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002238 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002239 cfg->line_out_pins[cfg->line_outs] =
2240 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002241 spec->mic_switch = 1;
2242 cfg->line_outs++;
2243 }
2244 break;
2245 }
2246
2247 return 0;
2248}
2249
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002250
2251static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2252{
2253 int i;
2254
2255 for (i = 0; i < spec->multiout.num_dacs; i++) {
2256 if (spec->multiout.dac_nids[i] == nid)
2257 return 1;
2258 }
2259
2260 return 0;
2261}
2262
Matt Porter3cc08dc2006-01-23 15:27:49 +01002263/*
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002264 * Fill in the dac_nids table from the parsed pin configuration
2265 * This function only works when every pin in line_out_pins[]
2266 * contains atleast one DAC in its connection list. Some 92xx
2267 * codecs are not connected directly to a DAC, such as the 9200
2268 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002269 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002270static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002271 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002272{
2273 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002274 int i, j, conn_len = 0;
2275 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2276 unsigned int wcaps, wtype;
2277
Mattc7d4b2f2005-06-27 14:59:41 +02002278 for (i = 0; i < cfg->line_outs; i++) {
2279 nid = cfg->line_out_pins[i];
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002280 conn_len = snd_hda_get_connections(codec, nid, conn,
2281 HDA_MAX_CONNECTIONS);
2282 for (j = 0; j < conn_len; j++) {
2283 wcaps = snd_hda_param_read(codec, conn[j],
2284 AC_PAR_AUDIO_WIDGET_CAP);
2285 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002286 if (wtype != AC_WID_AUD_OUT ||
2287 (wcaps & AC_WCAP_DIGITAL))
2288 continue;
2289 /* conn[j] is a DAC routed to this line-out */
2290 if (!is_in_dac_nids(spec, conn[j]))
2291 break;
2292 }
2293
2294 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002295 if (spec->multiout.num_dacs > 0) {
2296 /* we have already working output pins,
2297 * so let's drop the broken ones again
2298 */
2299 cfg->line_outs = spec->multiout.num_dacs;
2300 break;
2301 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002302 /* error out, no available DAC found */
2303 snd_printk(KERN_ERR
2304 "%s: No available DAC for pin 0x%x\n",
2305 __func__, nid);
2306 return -ENODEV;
2307 }
2308
2309 spec->multiout.dac_nids[i] = conn[j];
2310 spec->multiout.num_dacs++;
2311 if (conn_len > 1) {
2312 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002313 snd_hda_codec_write_cache(codec, nid, 0,
2314 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002315
2316 }
Mattc7d4b2f2005-06-27 14:59:41 +02002317 }
2318
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002319 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2320 spec->multiout.num_dacs,
2321 spec->multiout.dac_nids[0],
2322 spec->multiout.dac_nids[1],
2323 spec->multiout.dac_nids[2],
2324 spec->multiout.dac_nids[3],
2325 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002326 return 0;
2327}
2328
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002329/* create volume control/switch for the given prefx type */
2330static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2331{
2332 char name[32];
2333 int err;
2334
2335 sprintf(name, "%s Playback Volume", pfx);
2336 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2337 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2338 if (err < 0)
2339 return err;
2340 sprintf(name, "%s Playback Switch", pfx);
2341 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2342 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2343 if (err < 0)
2344 return err;
2345 return 0;
2346}
2347
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002348static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2349{
2350 if (!spec->multiout.hp_nid)
2351 spec->multiout.hp_nid = nid;
2352 else if (spec->multiout.num_dacs > 4) {
2353 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2354 return 1;
2355 } else {
2356 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2357 spec->multiout.num_dacs++;
2358 }
2359 return 0;
2360}
2361
2362static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2363{
2364 if (is_in_dac_nids(spec, nid))
2365 return 1;
2366 if (spec->multiout.hp_nid == nid)
2367 return 1;
2368 return 0;
2369}
2370
Mattc7d4b2f2005-06-27 14:59:41 +02002371/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002372static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002373 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002374{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002375 static const char *chname[4] = {
2376 "Front", "Surround", NULL /*CLFE*/, "Side"
2377 };
Mattc7d4b2f2005-06-27 14:59:41 +02002378 hda_nid_t nid;
2379 int i, err;
2380
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002381 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002382 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002383
2384
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002385 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002386 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002387 continue;
2388
2389 nid = spec->multiout.dac_nids[i];
2390
2391 if (i == 2) {
2392 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002393 err = create_controls(spec, "Center", nid, 1);
2394 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002395 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002396 err = create_controls(spec, "LFE", nid, 2);
2397 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002398 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002399
2400 wid_caps = get_wcaps(codec, nid);
2401
2402 if (wid_caps & AC_WCAP_LR_SWAP) {
2403 err = stac92xx_add_control(spec,
2404 STAC_CTL_WIDGET_CLFE_SWITCH,
2405 "Swap Center/LFE Playback Switch", nid);
2406
2407 if (err < 0)
2408 return err;
2409 }
2410
Mattc7d4b2f2005-06-27 14:59:41 +02002411 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002412 err = create_controls(spec, chname[i], nid, 3);
2413 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002414 return err;
2415 }
2416 }
2417
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002418 if (spec->line_switch) {
2419 nid = cfg->input_pins[AUTO_PIN_LINE];
2420 pincap = snd_hda_param_read(codec, nid,
2421 AC_PAR_PIN_CAP);
2422 if (pincap & AC_PINCAP_OUT) {
2423 err = stac92xx_add_control(spec,
2424 STAC_CTL_WIDGET_IO_SWITCH,
2425 "Line In as Output Switch", nid << 8);
2426 if (err < 0)
2427 return err;
2428 }
2429 }
Matt Porter403d1942005-11-29 15:00:51 +01002430
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002431 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002432 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002433 unsigned int mic_pin = AUTO_PIN_MIC;
2434again:
2435 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002436 def_conf = snd_hda_codec_read(codec, nid, 0,
2437 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002438 /* some laptops have an internal analog microphone
2439 * which can't be used as a output */
2440 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2441 pincap = snd_hda_param_read(codec, nid,
2442 AC_PAR_PIN_CAP);
2443 if (pincap & AC_PINCAP_OUT) {
2444 err = stac92xx_add_control(spec,
2445 STAC_CTL_WIDGET_IO_SWITCH,
2446 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002447 nid = snd_hda_codec_read(codec, nid, 0,
2448 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2449 if (!check_in_dac_nids(spec, nid))
2450 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002451 if (err < 0)
2452 return err;
2453 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002454 } else if (mic_pin == AUTO_PIN_MIC) {
2455 mic_pin = AUTO_PIN_FRONT_MIC;
2456 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002457 }
2458 }
Matt Porter403d1942005-11-29 15:00:51 +01002459
Mattc7d4b2f2005-06-27 14:59:41 +02002460 return 0;
2461}
2462
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002463/* add playback controls for Speaker and HP outputs */
2464static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2465 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002466{
2467 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002468 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002469 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002470
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002471 old_num_dacs = spec->multiout.num_dacs;
2472 for (i = 0; i < cfg->hp_outs; i++) {
2473 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2474 if (wid_caps & AC_WCAP_UNSOL_CAP)
2475 spec->hp_detect = 1;
2476 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2477 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2478 if (check_in_dac_nids(spec, nid))
2479 nid = 0;
2480 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002481 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002482 add_spec_dacs(spec, nid);
2483 }
2484 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002485 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002486 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2487 if (check_in_dac_nids(spec, nid))
2488 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002489 if (! nid)
2490 continue;
2491 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002492 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002493 for (i = 0; i < cfg->line_outs; i++) {
2494 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2495 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2496 if (check_in_dac_nids(spec, nid))
2497 nid = 0;
2498 if (! nid)
2499 continue;
2500 add_spec_dacs(spec, nid);
2501 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002502 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2503 static const char *pfxs[] = {
2504 "Speaker", "External Speaker", "Speaker2",
2505 };
2506 err = create_controls(spec, pfxs[i - old_num_dacs],
2507 spec->multiout.dac_nids[i], 3);
2508 if (err < 0)
2509 return err;
2510 }
2511 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002512 err = create_controls(spec, "Headphone",
2513 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002514 if (err < 0)
2515 return err;
2516 }
Mattc7d4b2f2005-06-27 14:59:41 +02002517
2518 return 0;
2519}
2520
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002521/* labels for mono mux outputs */
2522static const char *stac92xx_mono_labels[3] = {
2523 "DAC0", "DAC1", "Mixer"
2524};
2525
2526/* create mono mux for mono out on capable codecs */
2527static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2528{
2529 struct sigmatel_spec *spec = codec->spec;
2530 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2531 int i, num_cons;
2532 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2533
2534 num_cons = snd_hda_get_connections(codec,
2535 spec->mono_nid,
2536 con_lst,
2537 HDA_MAX_NUM_INPUTS);
2538 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2539 return -EINVAL;
2540
2541 for (i = 0; i < num_cons; i++) {
2542 mono_mux->items[mono_mux->num_items].label =
2543 stac92xx_mono_labels[i];
2544 mono_mux->items[mono_mux->num_items].index = i;
2545 mono_mux->num_items++;
2546 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002547
2548 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2549 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002550}
2551
Matt Porter8b657272006-10-26 17:12:59 +02002552/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002553static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002554 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2555 "Digital Mic 3", "Digital Mic 4"
2556};
2557
2558/* create playback/capture controls for input pins on dmic capable codecs */
2559static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2560 const struct auto_pin_cfg *cfg)
2561{
2562 struct sigmatel_spec *spec = codec->spec;
2563 struct hda_input_mux *dimux = &spec->private_dimux;
2564 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002565 int err, i, j;
2566 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002567
2568 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2569 dimux->items[dimux->num_items].index = 0;
2570 dimux->num_items++;
2571
2572 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002573 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002574 int index;
2575 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002576 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002577 unsigned int def_conf;
2578
2579 def_conf = snd_hda_codec_read(codec,
2580 spec->dmic_nids[i],
2581 0,
2582 AC_VERB_GET_CONFIG_DEFAULT,
2583 0);
2584 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2585 continue;
2586
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002587 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002588 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002589 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002590 con_lst,
2591 HDA_MAX_NUM_INPUTS);
2592 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002593 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002594 index = j;
2595 goto found;
2596 }
2597 continue;
2598found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002599 wcaps = get_wcaps(codec, nid);
2600
2601 if (wcaps & AC_WCAP_OUT_AMP) {
2602 sprintf(name, "%s Capture Volume",
2603 stac92xx_dmic_labels[dimux->num_items]);
2604
2605 err = stac92xx_add_control(spec,
2606 STAC_CTL_WIDGET_VOL,
2607 name,
2608 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2609 if (err < 0)
2610 return err;
2611 }
2612
Matt Porter8b657272006-10-26 17:12:59 +02002613 dimux->items[dimux->num_items].label =
2614 stac92xx_dmic_labels[dimux->num_items];
2615 dimux->items[dimux->num_items].index = index;
2616 dimux->num_items++;
2617 }
2618
2619 return 0;
2620}
2621
Mattc7d4b2f2005-06-27 14:59:41 +02002622/* create playback/capture controls for input pins */
2623static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2624{
2625 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002626 struct hda_input_mux *imux = &spec->private_imux;
2627 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2628 int i, j, k;
2629
2630 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002631 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002632
Takashi Iwai314634b2006-09-21 11:56:18 +02002633 if (!cfg->input_pins[i])
2634 continue;
2635 index = -1;
2636 for (j = 0; j < spec->num_muxes; j++) {
2637 int num_cons;
2638 num_cons = snd_hda_get_connections(codec,
2639 spec->mux_nids[j],
2640 con_lst,
2641 HDA_MAX_NUM_INPUTS);
2642 for (k = 0; k < num_cons; k++)
2643 if (con_lst[k] == cfg->input_pins[i]) {
2644 index = k;
2645 goto found;
2646 }
Mattc7d4b2f2005-06-27 14:59:41 +02002647 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002648 continue;
2649 found:
2650 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2651 imux->items[imux->num_items].index = index;
2652 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002653 }
2654
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002655 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002656 /*
2657 * Set the current input for the muxes.
2658 * The STAC9221 has two input muxes with identical source
2659 * NID lists. Hopefully this won't get confused.
2660 */
2661 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002662 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2663 AC_VERB_SET_CONNECT_SEL,
2664 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002665 }
2666 }
2667
Mattc7d4b2f2005-06-27 14:59:41 +02002668 return 0;
2669}
2670
Mattc7d4b2f2005-06-27 14:59:41 +02002671static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2672{
2673 struct sigmatel_spec *spec = codec->spec;
2674 int i;
2675
2676 for (i = 0; i < spec->autocfg.line_outs; i++) {
2677 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2678 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2679 }
2680}
2681
2682static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2683{
2684 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002685 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002686
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002687 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2688 hda_nid_t pin;
2689 pin = spec->autocfg.hp_pins[i];
2690 if (pin) /* connect to front */
2691 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2692 }
2693 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2694 hda_nid_t pin;
2695 pin = spec->autocfg.speaker_pins[i];
2696 if (pin) /* connect to front */
2697 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2698 }
Mattc7d4b2f2005-06-27 14:59:41 +02002699}
2700
Matt Porter3cc08dc2006-01-23 15:27:49 +01002701static 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 +02002702{
2703 struct sigmatel_spec *spec = codec->spec;
2704 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002705 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002706
Matt Porter8b657272006-10-26 17:12:59 +02002707 if ((err = snd_hda_parse_pin_def_config(codec,
2708 &spec->autocfg,
2709 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002710 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002711 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002712 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002713
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002714 /* If we have no real line-out pin and multiple hp-outs, HPs should
2715 * be set up as multi-channel outputs.
2716 */
2717 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2718 spec->autocfg.hp_outs > 1) {
2719 /* Copy hp_outs to line_outs, backup line_outs in
2720 * speaker_outs so that the following routines can handle
2721 * HP pins as primary outputs.
2722 */
2723 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2724 sizeof(spec->autocfg.line_out_pins));
2725 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2726 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2727 sizeof(spec->autocfg.hp_pins));
2728 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2729 hp_speaker_swap = 1;
2730 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002731 if (spec->autocfg.mono_out_pin) {
2732 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2733 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2734 u32 caps = query_amp_caps(codec,
2735 spec->autocfg.mono_out_pin, dir);
2736 hda_nid_t conn_list[1];
2737
2738 /* get the mixer node and then the mono mux if it exists */
2739 if (snd_hda_get_connections(codec,
2740 spec->autocfg.mono_out_pin, conn_list, 1) &&
2741 snd_hda_get_connections(codec, conn_list[0],
2742 conn_list, 1)) {
2743
2744 int wcaps = get_wcaps(codec, conn_list[0]);
2745 int wid_type = (wcaps & AC_WCAP_TYPE)
2746 >> AC_WCAP_TYPE_SHIFT;
2747 /* LR swap check, some stac925x have a mux that
2748 * changes the DACs output path instead of the
2749 * mono-mux path.
2750 */
2751 if (wid_type == AC_WID_AUD_SEL &&
2752 !(wcaps & AC_WCAP_LR_SWAP))
2753 spec->mono_nid = conn_list[0];
2754 }
2755 /* all mono outs have a least a mute/unmute switch */
2756 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2757 "Mono Playback Switch",
2758 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2759 1, 0, dir));
2760 if (err < 0)
2761 return err;
2762 /* check to see if there is volume support for the amp */
2763 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2764 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2765 "Mono Playback Volume",
2766 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2767 1, 0, dir));
2768 if (err < 0)
2769 return err;
2770 }
2771
2772 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2773 AC_PINCTL_OUT_EN);
2774 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002775
Matt Porter403d1942005-11-29 15:00:51 +01002776 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2777 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002778 if (spec->multiout.num_dacs == 0)
2779 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2780 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002781
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002782 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2783
2784 if (err < 0)
2785 return err;
2786
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002787 if (hp_speaker_swap == 1) {
2788 /* Restore the hp_outs and line_outs */
2789 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2790 sizeof(spec->autocfg.line_out_pins));
2791 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2792 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2793 sizeof(spec->autocfg.speaker_pins));
2794 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2795 memset(spec->autocfg.speaker_pins, 0,
2796 sizeof(spec->autocfg.speaker_pins));
2797 spec->autocfg.speaker_outs = 0;
2798 }
2799
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002800 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2801
2802 if (err < 0)
2803 return err;
2804
2805 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2806
2807 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002808 return err;
2809
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002810 if (spec->mono_nid > 0) {
2811 err = stac92xx_auto_create_mono_output_ctls(codec);
2812 if (err < 0)
2813 return err;
2814 }
2815
Matt Porter8b657272006-10-26 17:12:59 +02002816 if (spec->num_dmics > 0)
2817 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2818 &spec->autocfg)) < 0)
2819 return err;
2820
Mattc7d4b2f2005-06-27 14:59:41 +02002821 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002822 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002823 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002824
Takashi Iwai82bc9552006-03-21 11:24:42 +01002825 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002826 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002827 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002828 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002829
2830 if (spec->kctl_alloc)
2831 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2832
2833 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002834 if (!spec->dinput_mux)
2835 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002836 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002837
2838 return 1;
2839}
2840
Takashi Iwai82bc9552006-03-21 11:24:42 +01002841/* add playback controls for HP output */
2842static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2843 struct auto_pin_cfg *cfg)
2844{
2845 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002846 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002847 unsigned int wid_caps;
2848
2849 if (! pin)
2850 return 0;
2851
2852 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002853 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002854 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002855
2856 return 0;
2857}
2858
Richard Fish160ea0d2006-09-06 13:58:25 +02002859/* add playback controls for LFE output */
2860static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2861 struct auto_pin_cfg *cfg)
2862{
2863 struct sigmatel_spec *spec = codec->spec;
2864 int err;
2865 hda_nid_t lfe_pin = 0x0;
2866 int i;
2867
2868 /*
2869 * search speaker outs and line outs for a mono speaker pin
2870 * with an amp. If one is found, add LFE controls
2871 * for it.
2872 */
2873 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2874 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002875 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002876 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2877 if (wcaps == AC_WCAP_OUT_AMP)
2878 /* found a mono speaker with an amp, must be lfe */
2879 lfe_pin = pin;
2880 }
2881
2882 /* if speaker_outs is 0, then speakers may be in line_outs */
2883 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2884 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2885 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002886 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01002887 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02002888 AC_VERB_GET_CONFIG_DEFAULT,
2889 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01002890 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002891 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002892 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2893 if (wcaps == AC_WCAP_OUT_AMP)
2894 /* found a mono speaker with an amp,
2895 must be lfe */
2896 lfe_pin = pin;
2897 }
2898 }
2899 }
2900
2901 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002902 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002903 if (err < 0)
2904 return err;
2905 }
2906
2907 return 0;
2908}
2909
Mattc7d4b2f2005-06-27 14:59:41 +02002910static int stac9200_parse_auto_config(struct hda_codec *codec)
2911{
2912 struct sigmatel_spec *spec = codec->spec;
2913 int err;
2914
Kailang Yangdf694da2005-12-05 19:42:22 +01002915 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002916 return err;
2917
2918 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2919 return err;
2920
Takashi Iwai82bc9552006-03-21 11:24:42 +01002921 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2922 return err;
2923
Richard Fish160ea0d2006-09-06 13:58:25 +02002924 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2925 return err;
2926
Takashi Iwai82bc9552006-03-21 11:24:42 +01002927 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002928 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002929 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002930 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002931
2932 if (spec->kctl_alloc)
2933 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2934
2935 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002936 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002937
2938 return 1;
2939}
2940
Sam Revitch62fe78e2006-05-10 15:09:17 +02002941/*
2942 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2943 * funky external mute control using GPIO pins.
2944 */
2945
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002946static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01002947 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002948{
2949 unsigned int gpiostate, gpiomask, gpiodir;
2950
2951 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2952 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01002953 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002954
2955 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2956 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002957 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002958
2959 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2960 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01002961 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002962
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002963 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002964 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2965
2966 snd_hda_codec_write(codec, codec->afg, 0,
2967 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002968 snd_hda_codec_read(codec, codec->afg, 0,
2969 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002970
2971 msleep(1);
2972
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002973 snd_hda_codec_read(codec, codec->afg, 0,
2974 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002975}
2976
Takashi Iwai314634b2006-09-21 11:56:18 +02002977static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2978 unsigned int event)
2979{
2980 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002981 snd_hda_codec_write_cache(codec, nid, 0,
2982 AC_VERB_SET_UNSOLICITED_ENABLE,
2983 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002984}
2985
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002986static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2987{
2988 int i;
2989 for (i = 0; i < cfg->hp_outs; i++)
2990 if (cfg->hp_pins[i] == nid)
2991 return 1; /* nid is a HP-Out */
2992
2993 return 0; /* nid is not a HP-Out */
2994};
2995
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002996static void stac92xx_power_down(struct hda_codec *codec)
2997{
2998 struct sigmatel_spec *spec = codec->spec;
2999
3000 /* power down inactive DACs */
3001 hda_nid_t *dac;
3002 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003003 if (!is_in_dac_nids(spec, *dac) &&
3004 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003005 snd_hda_codec_write_cache(codec, *dac, 0,
3006 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3007}
3008
Mattc7d4b2f2005-06-27 14:59:41 +02003009static int stac92xx_init(struct hda_codec *codec)
3010{
3011 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003012 struct auto_pin_cfg *cfg = &spec->autocfg;
3013 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003014
Mattc7d4b2f2005-06-27 14:59:41 +02003015 snd_hda_sequence_write(codec, spec->init);
3016
Takashi Iwai82bc9552006-03-21 11:24:42 +01003017 /* set up pins */
3018 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003019 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003020 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003021 enable_pin_detect(codec, cfg->hp_pins[i],
3022 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003023 /* force to enable the first line-out; the others are set up
3024 * in unsol_event
3025 */
3026 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3027 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003028 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003029 /* fake event to set up pins */
3030 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3031 } else {
3032 stac92xx_auto_init_multi_out(codec);
3033 stac92xx_auto_init_hp_out(codec);
3034 }
3035 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003036 hda_nid_t nid = cfg->input_pins[i];
3037 if (nid) {
3038 unsigned int pinctl = AC_PINCTL_IN_EN;
3039 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3040 pinctl |= stac92xx_get_vref(codec, nid);
3041 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3042 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003043 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003044 for (i = 0; i < spec->num_dmics; i++)
3045 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3046 AC_PINCTL_IN_EN);
3047 for (i = 0; i < spec->num_pwrs; i++) {
3048 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3049 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3050 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3051 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003052 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3053 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003054 /* outputs are only ports capable of power management
3055 * any attempts on powering down a input port cause the
3056 * referenced VREF to act quirky.
3057 */
3058 if (pinctl & AC_PINCTL_IN_EN)
3059 continue;
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003060 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
3061 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003062 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3063 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3064 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003065 if (spec->dac_list)
3066 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003067 if (cfg->dig_out_pin)
3068 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3069 AC_PINCTL_OUT_EN);
3070 if (cfg->dig_in_pin)
3071 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3072 AC_PINCTL_IN_EN);
3073
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003074 stac_gpio_set(codec, spec->gpio_mask,
3075 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003076
Mattc7d4b2f2005-06-27 14:59:41 +02003077 return 0;
3078}
3079
Matt2f2f4252005-04-13 14:45:30 +02003080static void stac92xx_free(struct hda_codec *codec)
3081{
Mattc7d4b2f2005-06-27 14:59:41 +02003082 struct sigmatel_spec *spec = codec->spec;
3083 int i;
3084
3085 if (! spec)
3086 return;
3087
3088 if (spec->kctl_alloc) {
3089 for (i = 0; i < spec->num_kctl_used; i++)
3090 kfree(spec->kctl_alloc[i].name);
3091 kfree(spec->kctl_alloc);
3092 }
3093
Richard Fish11b44bb2006-08-23 18:31:34 +02003094 if (spec->bios_pin_configs)
3095 kfree(spec->bios_pin_configs);
3096
Mattc7d4b2f2005-06-27 14:59:41 +02003097 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02003098}
3099
Matt4e550962005-07-04 17:51:39 +02003100static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3101 unsigned int flag)
3102{
3103 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3104 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003105
Takashi Iwaif9acba42007-05-29 18:01:06 +02003106 if (pin_ctl & AC_PINCTL_IN_EN) {
3107 /*
3108 * we need to check the current set-up direction of
3109 * shared input pins since they can be switched via
3110 * "xxx as Output" mixer switch
3111 */
3112 struct sigmatel_spec *spec = codec->spec;
3113 struct auto_pin_cfg *cfg = &spec->autocfg;
3114 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3115 spec->line_switch) ||
3116 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3117 spec->mic_switch))
3118 return;
3119 }
3120
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003121 /* if setting pin direction bits, clear the current
3122 direction bits first */
3123 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3124 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3125
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003126 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003127 AC_VERB_SET_PIN_WIDGET_CONTROL,
3128 pin_ctl | flag);
3129}
3130
3131static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3132 unsigned int flag)
3133{
3134 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3135 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003136 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003137 AC_VERB_SET_PIN_WIDGET_CONTROL,
3138 pin_ctl & ~flag);
3139}
3140
Jiang Zhe40c1d302007-11-12 13:05:16 +01003141static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003142{
3143 if (!nid)
3144 return 0;
3145 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003146 & (1 << 31)) {
3147 unsigned int pinctl;
3148 pinctl = snd_hda_codec_read(codec, nid, 0,
3149 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3150 if (pinctl & AC_PINCTL_IN_EN)
3151 return 0; /* mic- or line-input */
3152 else
3153 return 1; /* HP-output */
3154 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003155 return 0;
3156}
3157
3158static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003159{
3160 struct sigmatel_spec *spec = codec->spec;
3161 struct auto_pin_cfg *cfg = &spec->autocfg;
3162 int i, presence;
3163
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003164 presence = 0;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003165 if (spec->gpio_mute)
3166 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3167 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3168
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003169 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003170 if (presence)
3171 break;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003172 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003173 }
Matt4e550962005-07-04 17:51:39 +02003174
3175 if (presence) {
3176 /* disable lineouts, enable hp */
3177 for (i = 0; i < cfg->line_outs; i++)
3178 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3179 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003180 for (i = 0; i < cfg->speaker_outs; i++)
3181 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3182 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003183 } else {
3184 /* enable lineouts, disable hp */
3185 for (i = 0; i < cfg->line_outs; i++)
3186 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3187 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003188 for (i = 0; i < cfg->speaker_outs; i++)
3189 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3190 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003191 }
3192}
3193
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003194static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3195{
3196 struct sigmatel_spec *spec = codec->spec;
3197 hda_nid_t nid = spec->pwr_nids[idx];
3198 int presence, val;
3199 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3200 & 0x000000ff;
3201 presence = get_hp_pin_presence(codec, nid);
3202 idx = 1 << idx;
3203
3204 if (presence)
3205 val &= ~idx;
3206 else
3207 val |= idx;
3208
3209 /* power down unused output ports */
3210 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3211};
3212
Takashi Iwai314634b2006-09-21 11:56:18 +02003213static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3214{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003215 struct sigmatel_spec *spec = codec->spec;
3216 int idx = res >> 26 & 0x0f;
3217
3218 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003219 case STAC_HP_EVENT:
3220 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003221 /* fallthru */
3222 case STAC_PWR_EVENT:
3223 if (spec->num_pwrs > 0)
3224 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003225 }
3226}
3227
Takashi Iwaicb53c622007-08-10 17:21:45 +02003228#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003229static int stac92xx_resume(struct hda_codec *codec)
3230{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003231 struct sigmatel_spec *spec = codec->spec;
3232
Richard Fish11b44bb2006-08-23 18:31:34 +02003233 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003234 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003235 stac_gpio_set(codec, spec->gpio_mask,
3236 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003237 snd_hda_codec_resume_amp(codec);
3238 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003239 /* power down inactive DACs */
3240 if (spec->dac_list)
3241 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003242 /* invoke unsolicited event to reset the HP state */
3243 if (spec->hp_detect)
3244 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003245 return 0;
3246}
3247#endif
3248
Matt2f2f4252005-04-13 14:45:30 +02003249static struct hda_codec_ops stac92xx_patch_ops = {
3250 .build_controls = stac92xx_build_controls,
3251 .build_pcms = stac92xx_build_pcms,
3252 .init = stac92xx_init,
3253 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003254 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003255#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003256 .resume = stac92xx_resume,
3257#endif
Matt2f2f4252005-04-13 14:45:30 +02003258};
3259
3260static int patch_stac9200(struct hda_codec *codec)
3261{
3262 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003263 int err;
Matt2f2f4252005-04-13 14:45:30 +02003264
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003265 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003266 if (spec == NULL)
3267 return -ENOMEM;
3268
3269 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003270 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003271 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003272 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3273 stac9200_models,
3274 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003275 if (spec->board_config < 0) {
3276 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3277 err = stac92xx_save_bios_config_regs(codec);
3278 if (err < 0) {
3279 stac92xx_free(codec);
3280 return err;
3281 }
3282 spec->pin_configs = spec->bios_pin_configs;
3283 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003284 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3285 stac92xx_set_config_regs(codec);
3286 }
Matt2f2f4252005-04-13 14:45:30 +02003287
3288 spec->multiout.max_channels = 2;
3289 spec->multiout.num_dacs = 1;
3290 spec->multiout.dac_nids = stac9200_dac_nids;
3291 spec->adc_nids = stac9200_adc_nids;
3292 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003293 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003294 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003295 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003296 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003297
Tobin Davisbf277782008-02-03 20:31:47 +01003298 if (spec->board_config == STAC_9200_GATEWAY ||
3299 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003300 spec->init = stac9200_eapd_init;
3301 else
3302 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003303 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003304
3305 err = stac9200_parse_auto_config(codec);
3306 if (err < 0) {
3307 stac92xx_free(codec);
3308 return err;
3309 }
Matt2f2f4252005-04-13 14:45:30 +02003310
3311 codec->patch_ops = stac92xx_patch_ops;
3312
3313 return 0;
3314}
3315
Tobin Davis8e21c342007-01-08 11:04:17 +01003316static int patch_stac925x(struct hda_codec *codec)
3317{
3318 struct sigmatel_spec *spec;
3319 int err;
3320
3321 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3322 if (spec == NULL)
3323 return -ENOMEM;
3324
3325 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003326 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003327 spec->pin_nids = stac925x_pin_nids;
3328 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3329 stac925x_models,
3330 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003331 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003332 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003333 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3334 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003335 err = stac92xx_save_bios_config_regs(codec);
3336 if (err < 0) {
3337 stac92xx_free(codec);
3338 return err;
3339 }
3340 spec->pin_configs = spec->bios_pin_configs;
3341 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3342 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3343 stac92xx_set_config_regs(codec);
3344 }
3345
3346 spec->multiout.max_channels = 2;
3347 spec->multiout.num_dacs = 1;
3348 spec->multiout.dac_nids = stac925x_dac_nids;
3349 spec->adc_nids = stac925x_adc_nids;
3350 spec->mux_nids = stac925x_mux_nids;
3351 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003352 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003353 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003354 switch (codec->vendor_id) {
3355 case 0x83847632: /* STAC9202 */
3356 case 0x83847633: /* STAC9202D */
3357 case 0x83847636: /* STAC9251 */
3358 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003359 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003360 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003361 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3362 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003363 break;
3364 default:
3365 spec->num_dmics = 0;
3366 break;
3367 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003368
3369 spec->init = stac925x_core_init;
3370 spec->mixer = stac925x_mixer;
3371
3372 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003373 if (!err) {
3374 if (spec->board_config < 0) {
3375 printk(KERN_WARNING "hda_codec: No auto-config is "
3376 "available, default to model=ref\n");
3377 spec->board_config = STAC_925x_REF;
3378 goto again;
3379 }
3380 err = -EINVAL;
3381 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003382 if (err < 0) {
3383 stac92xx_free(codec);
3384 return err;
3385 }
3386
3387 codec->patch_ops = stac92xx_patch_ops;
3388
3389 return 0;
3390}
3391
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003392static struct hda_input_mux stac92hd73xx_dmux = {
3393 .num_items = 4,
3394 .items = {
3395 { "Analog Inputs", 0x0b },
3396 { "CD", 0x08 },
3397 { "Digital Mic 1", 0x09 },
3398 { "Digital Mic 2", 0x0a },
3399 }
3400};
3401
3402static int patch_stac92hd73xx(struct hda_codec *codec)
3403{
3404 struct sigmatel_spec *spec;
3405 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3406 int err = 0;
3407
3408 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3409 if (spec == NULL)
3410 return -ENOMEM;
3411
3412 codec->spec = spec;
3413 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3414 spec->pin_nids = stac92hd73xx_pin_nids;
3415 spec->board_config = snd_hda_check_board_config(codec,
3416 STAC_92HD73XX_MODELS,
3417 stac92hd73xx_models,
3418 stac92hd73xx_cfg_tbl);
3419again:
3420 if (spec->board_config < 0) {
3421 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3422 " STAC92HD73XX, using BIOS defaults\n");
3423 err = stac92xx_save_bios_config_regs(codec);
3424 if (err < 0) {
3425 stac92xx_free(codec);
3426 return err;
3427 }
3428 spec->pin_configs = spec->bios_pin_configs;
3429 } else {
3430 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3431 stac92xx_set_config_regs(codec);
3432 }
3433
3434 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3435 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3436
3437 if (spec->multiout.num_dacs < 0) {
3438 printk(KERN_WARNING "hda_codec: Could not determine "
3439 "number of channels defaulting to DAC count\n");
3440 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3441 }
3442
3443 switch (spec->multiout.num_dacs) {
3444 case 0x3: /* 6 Channel */
3445 spec->mixer = stac92hd73xx_6ch_mixer;
3446 spec->init = stac92hd73xx_6ch_core_init;
3447 break;
3448 case 0x4: /* 8 Channel */
3449 spec->multiout.hp_nid = 0x18;
3450 spec->mixer = stac92hd73xx_8ch_mixer;
3451 spec->init = stac92hd73xx_8ch_core_init;
3452 break;
3453 case 0x5: /* 10 Channel */
3454 spec->multiout.hp_nid = 0x19;
3455 spec->mixer = stac92hd73xx_10ch_mixer;
3456 spec->init = stac92hd73xx_10ch_core_init;
3457 };
3458
3459 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3460 spec->aloopback_mask = 0x01;
3461 spec->aloopback_shift = 8;
3462
3463 spec->mux_nids = stac92hd73xx_mux_nids;
3464 spec->adc_nids = stac92hd73xx_adc_nids;
3465 spec->dmic_nids = stac92hd73xx_dmic_nids;
3466 spec->dmux_nids = stac92hd73xx_dmux_nids;
3467
3468 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3469 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003470 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003471 spec->dinput_mux = &stac92hd73xx_dmux;
3472 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003473 spec->gpio_mask = spec->gpio_dir = 0x1;
3474 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003475
Matthew Ranostaya7662642008-02-21 07:51:14 +01003476 switch (spec->board_config) {
3477 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003478 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003479 switch (codec->subsystem_id) {
3480 case 0x1028025e: /* Analog Mics */
3481 case 0x1028025f:
3482 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3483 spec->num_dmics = 0;
3484 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003485 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003486 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003487 spec->init = dell_m6_core_init;
3488 /* fall-through */
3489 case 0x10280254:
3490 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003491 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3492 spec->num_dmics = 1;
3493 break;
3494 case 0x10280256: /* Both */
3495 case 0x10280057:
3496 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3497 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3498 spec->num_dmics = 1;
3499 break;
3500 }
3501 break;
3502 default:
3503 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3504 }
3505
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003506 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3507 spec->pwr_nids = stac92hd73xx_pwr_nids;
3508
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003509 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3510
3511 if (!err) {
3512 if (spec->board_config < 0) {
3513 printk(KERN_WARNING "hda_codec: No auto-config is "
3514 "available, default to model=ref\n");
3515 spec->board_config = STAC_92HD73XX_REF;
3516 goto again;
3517 }
3518 err = -EINVAL;
3519 }
3520
3521 if (err < 0) {
3522 stac92xx_free(codec);
3523 return err;
3524 }
3525
3526 codec->patch_ops = stac92xx_patch_ops;
3527
3528 return 0;
3529}
3530
Matthew Ranostaye035b842007-11-06 11:53:55 +01003531static int patch_stac92hd71bxx(struct hda_codec *codec)
3532{
3533 struct sigmatel_spec *spec;
3534 int err = 0;
3535
3536 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3537 if (spec == NULL)
3538 return -ENOMEM;
3539
3540 codec->spec = spec;
3541 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3542 spec->pin_nids = stac92hd71bxx_pin_nids;
3543 spec->board_config = snd_hda_check_board_config(codec,
3544 STAC_92HD71BXX_MODELS,
3545 stac92hd71bxx_models,
3546 stac92hd71bxx_cfg_tbl);
3547again:
3548 if (spec->board_config < 0) {
3549 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3550 " STAC92HD71BXX, using BIOS defaults\n");
3551 err = stac92xx_save_bios_config_regs(codec);
3552 if (err < 0) {
3553 stac92xx_free(codec);
3554 return err;
3555 }
3556 spec->pin_configs = spec->bios_pin_configs;
3557 } else {
3558 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3559 stac92xx_set_config_regs(codec);
3560 }
3561
Matthew Ranostay541eee82007-12-14 12:08:04 +01003562 switch (codec->vendor_id) {
3563 case 0x111d76b6: /* 4 Port without Analog Mixer */
3564 case 0x111d76b7:
3565 case 0x111d76b4: /* 6 Port without Analog Mixer */
3566 case 0x111d76b5:
3567 spec->mixer = stac92hd71bxx_mixer;
3568 spec->init = stac92hd71bxx_core_init;
3569 break;
3570 default:
3571 spec->mixer = stac92hd71bxx_analog_mixer;
3572 spec->init = stac92hd71bxx_analog_core_init;
3573 }
3574
3575 spec->aloopback_mask = 0x20;
3576 spec->aloopback_shift = 0;
3577
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003578 /* GPIO0 High = EAPD */
3579 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003580
Matthew Ranostaye035b842007-11-06 11:53:55 +01003581 spec->mux_nids = stac92hd71bxx_mux_nids;
3582 spec->adc_nids = stac92hd71bxx_adc_nids;
3583 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003584 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003585
3586 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3587 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3588 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003589 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003590
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003591 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3592 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3593
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01003594 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003595 spec->multiout.hp_nid = 0x11;
3596 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3597
3598 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3599 if (!err) {
3600 if (spec->board_config < 0) {
3601 printk(KERN_WARNING "hda_codec: No auto-config is "
3602 "available, default to model=ref\n");
3603 spec->board_config = STAC_92HD71BXX_REF;
3604 goto again;
3605 }
3606 err = -EINVAL;
3607 }
3608
3609 if (err < 0) {
3610 stac92xx_free(codec);
3611 return err;
3612 }
3613
3614 codec->patch_ops = stac92xx_patch_ops;
3615
3616 return 0;
3617};
3618
Matt2f2f4252005-04-13 14:45:30 +02003619static int patch_stac922x(struct hda_codec *codec)
3620{
3621 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003622 int err;
Matt2f2f4252005-04-13 14:45:30 +02003623
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003624 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003625 if (spec == NULL)
3626 return -ENOMEM;
3627
3628 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003629 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003630 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003631 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3632 stac922x_models,
3633 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003634 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003635 spec->gpio_mask = spec->gpio_dir = 0x03;
3636 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003637 /* Intel Macs have all same PCI SSID, so we need to check
3638 * codec SSID to distinguish the exact models
3639 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003640 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003641 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003642
3643 case 0x106b0800:
3644 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003645 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003646 case 0x106b0600:
3647 case 0x106b0700:
3648 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003649 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003650 case 0x106b0e00:
3651 case 0x106b0f00:
3652 case 0x106b1600:
3653 case 0x106b1700:
3654 case 0x106b0200:
3655 case 0x106b1e00:
3656 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003657 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003658 case 0x106b1a00:
3659 case 0x00000100:
3660 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003661 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003662 case 0x106b0a00:
3663 case 0x106b2200:
3664 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003665 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003666 }
3667 }
3668
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003669 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003670 if (spec->board_config < 0) {
3671 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3672 "using BIOS defaults\n");
3673 err = stac92xx_save_bios_config_regs(codec);
3674 if (err < 0) {
3675 stac92xx_free(codec);
3676 return err;
3677 }
3678 spec->pin_configs = spec->bios_pin_configs;
3679 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003680 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3681 stac92xx_set_config_regs(codec);
3682 }
Matt2f2f4252005-04-13 14:45:30 +02003683
Matt2f2f4252005-04-13 14:45:30 +02003684 spec->adc_nids = stac922x_adc_nids;
3685 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003686 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003687 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003688 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003689 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003690
3691 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003692 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003693
3694 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003695
Matt Porter3cc08dc2006-01-23 15:27:49 +01003696 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003697 if (!err) {
3698 if (spec->board_config < 0) {
3699 printk(KERN_WARNING "hda_codec: No auto-config is "
3700 "available, default to model=ref\n");
3701 spec->board_config = STAC_D945_REF;
3702 goto again;
3703 }
3704 err = -EINVAL;
3705 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003706 if (err < 0) {
3707 stac92xx_free(codec);
3708 return err;
3709 }
3710
3711 codec->patch_ops = stac92xx_patch_ops;
3712
Takashi Iwai807a46362007-05-29 19:01:37 +02003713 /* Fix Mux capture level; max to 2 */
3714 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3715 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3716 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3717 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3718 (0 << AC_AMPCAP_MUTE_SHIFT));
3719
Matt Porter3cc08dc2006-01-23 15:27:49 +01003720 return 0;
3721}
3722
3723static int patch_stac927x(struct hda_codec *codec)
3724{
3725 struct sigmatel_spec *spec;
3726 int err;
3727
3728 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3729 if (spec == NULL)
3730 return -ENOMEM;
3731
3732 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003733 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003734 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003735 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3736 stac927x_models,
3737 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003738 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003739 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3740 if (spec->board_config < 0)
3741 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3742 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003743 err = stac92xx_save_bios_config_regs(codec);
3744 if (err < 0) {
3745 stac92xx_free(codec);
3746 return err;
3747 }
3748 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003749 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003750 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3751 stac92xx_set_config_regs(codec);
3752 }
3753
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003754 spec->adc_nids = stac927x_adc_nids;
3755 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3756 spec->mux_nids = stac927x_mux_nids;
3757 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003758 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003759 spec->multiout.dac_nids = spec->dac_nids;
3760
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003761 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003762 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003763 case STAC_D965_5ST:
3764 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003765 spec->gpio_mask = spec->gpio_dir = 0x01;
3766 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003767 spec->num_dmics = 0;
3768
Tobin Davis93ed1502006-09-01 21:03:12 +02003769 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003770 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003771 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003772 case STAC_DELL_BIOS:
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003773 /* configure the analog microphone on some laptops */
3774 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003775 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003776 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003777 /* correct the front input jack as a mic */
3778 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3779 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003780 case STAC_DELL_3ST:
3781 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003782 spec->gpio_mask = spec->gpio_dir = 0x04;
3783 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003784 spec->dmic_nids = stac927x_dmic_nids;
3785 spec->num_dmics = STAC927X_NUM_DMICS;
3786
Tobin Davis93ed1502006-09-01 21:03:12 +02003787 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003788 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003789 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003790 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003791 break;
3792 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003793 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003794 spec->gpio_mask = spec->gpio_dir = 0x1;
3795 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003796 spec->num_dmics = 0;
3797
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003798 spec->init = stac927x_core_init;
3799 spec->mixer = stac927x_mixer;
3800 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003801
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003802 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003803 spec->aloopback_mask = 0x40;
3804 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003805
Matt Porter3cc08dc2006-01-23 15:27:49 +01003806 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003807 if (!err) {
3808 if (spec->board_config < 0) {
3809 printk(KERN_WARNING "hda_codec: No auto-config is "
3810 "available, default to model=ref\n");
3811 spec->board_config = STAC_D965_REF;
3812 goto again;
3813 }
3814 err = -EINVAL;
3815 }
Mattc7d4b2f2005-06-27 14:59:41 +02003816 if (err < 0) {
3817 stac92xx_free(codec);
3818 return err;
3819 }
Matt2f2f4252005-04-13 14:45:30 +02003820
3821 codec->patch_ops = stac92xx_patch_ops;
3822
Takashi Iwai52987652008-01-16 16:09:47 +01003823 /*
3824 * !!FIXME!!
3825 * The STAC927x seem to require fairly long delays for certain
3826 * command sequences. With too short delays (even if the answer
3827 * is set to RIRB properly), it results in the silence output
3828 * on some hardwares like Dell.
3829 *
3830 * The below flag enables the longer delay (see get_response
3831 * in hda_intel.c).
3832 */
3833 codec->bus->needs_damn_long_delay = 1;
3834
Matt2f2f4252005-04-13 14:45:30 +02003835 return 0;
3836}
3837
Matt Porterf3302a52006-07-31 12:49:34 +02003838static int patch_stac9205(struct hda_codec *codec)
3839{
3840 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003841 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003842
3843 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3844 if (spec == NULL)
3845 return -ENOMEM;
3846
3847 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003848 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003849 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003850 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3851 stac9205_models,
3852 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003853 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003854 if (spec->board_config < 0) {
3855 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3856 err = stac92xx_save_bios_config_regs(codec);
3857 if (err < 0) {
3858 stac92xx_free(codec);
3859 return err;
3860 }
3861 spec->pin_configs = spec->bios_pin_configs;
3862 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003863 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3864 stac92xx_set_config_regs(codec);
3865 }
3866
3867 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003868 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003869 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003870 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003871 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003872 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003873 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003874 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003875 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003876
3877 spec->init = stac9205_core_init;
3878 spec->mixer = stac9205_mixer;
3879
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003880 spec->aloopback_mask = 0x40;
3881 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003882 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003883
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003884 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003885 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003886 /* Enable SPDIF in/out */
3887 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3888 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003889
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003890 /* Enable unsol response for GPIO4/Dock HP connection */
3891 snd_hda_codec_write(codec, codec->afg, 0,
3892 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3893 snd_hda_codec_write_cache(codec, codec->afg, 0,
3894 AC_VERB_SET_UNSOLICITED_ENABLE,
3895 (AC_USRSP_EN | STAC_HP_EVENT));
3896
3897 spec->gpio_dir = 0x0b;
3898 spec->gpio_mask = 0x1b;
3899 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003900 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003901 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003902 */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003903 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003904 break;
3905 default:
3906 /* GPIO0 High = EAPD */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003907 spec->gpio_mask = spec->gpio_dir = 0x1;
3908 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003909 break;
3910 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003911
Matt Porterf3302a52006-07-31 12:49:34 +02003912 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003913 if (!err) {
3914 if (spec->board_config < 0) {
3915 printk(KERN_WARNING "hda_codec: No auto-config is "
3916 "available, default to model=ref\n");
3917 spec->board_config = STAC_9205_REF;
3918 goto again;
3919 }
3920 err = -EINVAL;
3921 }
Matt Porterf3302a52006-07-31 12:49:34 +02003922 if (err < 0) {
3923 stac92xx_free(codec);
3924 return err;
3925 }
3926
3927 codec->patch_ops = stac92xx_patch_ops;
3928
3929 return 0;
3930}
3931
Matt2f2f4252005-04-13 14:45:30 +02003932/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003933 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003934 */
3935
Guillaume Munch99ccc562006-08-16 19:35:12 +02003936/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003937static hda_nid_t vaio_dacs[] = { 0x2 };
3938#define VAIO_HP_DAC 0x5
3939static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3940static hda_nid_t vaio_mux_nids[] = { 0x15 };
3941
3942static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003943 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003944 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003945 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003946 { "Mic Jack", 0x1 },
3947 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003948 { "PCM", 0x3 },
3949 }
3950};
3951
3952static struct hda_verb vaio_init[] = {
3953 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003954 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003955 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3956 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3957 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3958 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003959 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003960 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3961 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3962 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3963 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3964 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3965 {}
3966};
3967
Guillaume Munch6d859062006-08-22 17:15:47 +02003968static struct hda_verb vaio_ar_init[] = {
3969 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3970 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3971 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3972 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3973/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3974 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003975 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003976 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3977 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3978/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3979 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3980 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3981 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3982 {}
3983};
3984
Takashi Iwaidb064e52006-03-16 16:04:58 +01003985/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003986static struct hda_bind_ctls vaio_bind_master_vol = {
3987 .ops = &snd_hda_bind_vol,
3988 .values = {
3989 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3990 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3991 0
3992 },
3993};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003994
3995/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003996static struct hda_bind_ctls vaio_bind_master_sw = {
3997 .ops = &snd_hda_bind_sw,
3998 .values = {
3999 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4000 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4001 0,
4002 },
4003};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004004
4005static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004006 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4007 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004008 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4009 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4010 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4011 {
4012 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4013 .name = "Capture Source",
4014 .count = 1,
4015 .info = stac92xx_mux_enum_info,
4016 .get = stac92xx_mux_enum_get,
4017 .put = stac92xx_mux_enum_put,
4018 },
4019 {}
4020};
4021
Guillaume Munch6d859062006-08-22 17:15:47 +02004022static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004023 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4024 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004025 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4026 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4027 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4028 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4029 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4030 {
4031 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4032 .name = "Capture Source",
4033 .count = 1,
4034 .info = stac92xx_mux_enum_info,
4035 .get = stac92xx_mux_enum_get,
4036 .put = stac92xx_mux_enum_put,
4037 },
4038 {}
4039};
4040
4041static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004042 .build_controls = stac92xx_build_controls,
4043 .build_pcms = stac92xx_build_pcms,
4044 .init = stac92xx_init,
4045 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004046#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004047 .resume = stac92xx_resume,
4048#endif
4049};
4050
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004051static int stac9872_vaio_init(struct hda_codec *codec)
4052{
4053 int err;
4054
4055 err = stac92xx_init(codec);
4056 if (err < 0)
4057 return err;
4058 if (codec->patch_ops.unsol_event)
4059 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4060 return 0;
4061}
4062
4063static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4064{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004065 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004066 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4067 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4068 } else {
4069 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4070 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4071 }
4072}
4073
4074static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4075{
4076 switch (res >> 26) {
4077 case STAC_HP_EVENT:
4078 stac9872_vaio_hp_detect(codec, res);
4079 break;
4080 }
4081}
4082
4083static struct hda_codec_ops stac9872_vaio_patch_ops = {
4084 .build_controls = stac92xx_build_controls,
4085 .build_pcms = stac92xx_build_pcms,
4086 .init = stac9872_vaio_init,
4087 .free = stac92xx_free,
4088 .unsol_event = stac9872_vaio_unsol_event,
4089#ifdef CONFIG_PM
4090 .resume = stac92xx_resume,
4091#endif
4092};
4093
Guillaume Munch6d859062006-08-22 17:15:47 +02004094enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4095 CXD9872RD_VAIO,
4096 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4097 STAC9872AK_VAIO,
4098 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4099 STAC9872K_VAIO,
4100 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004101 CXD9872AKD_VAIO,
4102 STAC_9872_MODELS,
4103};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004104
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004105static const char *stac9872_models[STAC_9872_MODELS] = {
4106 [CXD9872RD_VAIO] = "vaio",
4107 [CXD9872AKD_VAIO] = "vaio-ar",
4108};
4109
4110static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4111 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4112 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4113 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004114 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004115 {}
4116};
4117
Guillaume Munch6d859062006-08-22 17:15:47 +02004118static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004119{
4120 struct sigmatel_spec *spec;
4121 int board_config;
4122
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004123 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4124 stac9872_models,
4125 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004126 if (board_config < 0)
4127 /* unknown config, let generic-parser do its job... */
4128 return snd_hda_parse_generic_codec(codec);
4129
4130 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4131 if (spec == NULL)
4132 return -ENOMEM;
4133
4134 codec->spec = spec;
4135 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004136 case CXD9872RD_VAIO:
4137 case STAC9872AK_VAIO:
4138 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004139 spec->mixer = vaio_mixer;
4140 spec->init = vaio_init;
4141 spec->multiout.max_channels = 2;
4142 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4143 spec->multiout.dac_nids = vaio_dacs;
4144 spec->multiout.hp_nid = VAIO_HP_DAC;
4145 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4146 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004147 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004148 spec->input_mux = &vaio_mux;
4149 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004150 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004151 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004152
4153 case CXD9872AKD_VAIO:
4154 spec->mixer = vaio_ar_mixer;
4155 spec->init = vaio_ar_init;
4156 spec->multiout.max_channels = 2;
4157 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4158 spec->multiout.dac_nids = vaio_dacs;
4159 spec->multiout.hp_nid = VAIO_HP_DAC;
4160 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004161 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004162 spec->adc_nids = vaio_adcs;
4163 spec->input_mux = &vaio_mux;
4164 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004165 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004166 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004167 }
4168
Takashi Iwaidb064e52006-03-16 16:04:58 +01004169 return 0;
4170}
4171
4172
4173/*
Matt2f2f4252005-04-13 14:45:30 +02004174 * patch entries
4175 */
4176struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4177 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4178 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4179 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4180 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4181 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4182 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4183 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004184 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4185 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4186 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4187 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4188 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4189 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004190 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4191 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4192 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4193 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4194 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4195 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4196 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4197 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4198 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4199 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004200 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4201 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4202 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4203 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4204 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4205 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004206 /* The following does not take into account .id=0x83847661 when subsys =
4207 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4208 * currently not fully supported.
4209 */
4210 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4211 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4212 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004213 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4214 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4215 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4216 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4217 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4218 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4219 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4220 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004221 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4222 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004223 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004224 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4225 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4226 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4227 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4228 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4229 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4230 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4231 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4232 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004233 {} /* terminator */
4234};