blob: 6c85e7e81034fc95dda719f3fd4830a8f79686cf [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 Ranostay4fe51952008-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 Ranostay52fe0f92008-02-29 12:08:20 +0100537static struct hda_verb dell_m6_core_init[] = {
538 /* set master volume and direct control */
539 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
540 /* setup audio connections */
541 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x00},
542 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x01},
543 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
544 /* setup adcs to point to mixer */
545 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
546 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
547 /* setup import muxs */
548 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
549 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
550 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
551 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
552 {}
553};
554
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100555static struct hda_verb stac92hd73xx_8ch_core_init[] = {
556 /* set master volume and direct control */
557 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
558 /* setup audio connections */
559 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
560 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
561 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
562 /* connect hp ports to dac3 */
563 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
564 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
565 /* setup adcs to point to mixer */
566 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
567 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100568 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
569 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
570 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
571 /* setup import muxs */
572 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
573 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
574 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
575 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
576 {}
577};
578
579static struct hda_verb stac92hd73xx_10ch_core_init[] = {
580 /* set master volume and direct control */
581 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
582 /* setup audio connections */
583 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
584 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
585 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
586 /* dac3 is connected to import3 mux */
587 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
588 /* connect hp ports to dac4 */
589 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
590 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
591 /* setup adcs to point to mixer */
592 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
593 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100594 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
595 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
596 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
597 /* setup import muxs */
598 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
599 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
600 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
601 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
602 {}
603};
604
Matthew Ranostaye035b842007-11-06 11:53:55 +0100605static struct hda_verb stac92hd71bxx_core_init[] = {
606 /* set master volume and direct control */
607 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
608 /* connect headphone jack to dac1 */
609 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100610 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
611 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
612 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
613 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
614 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100615};
616
617static struct hda_verb stac92hd71bxx_analog_core_init[] = {
618 /* set master volume and direct control */
619 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
620 /* connect headphone jack to dac1 */
621 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100622 /* connect ports 0d and 0f to audio mixer */
623 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
624 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100625 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100626 /* unmute dac0 input in audio mixer */
627 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100628 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
629 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
630 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
631 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100632 {}
633};
634
Tobin Davis8e21c342007-01-08 11:04:17 +0100635static struct hda_verb stac925x_core_init[] = {
636 /* set dac0mux for dac converter */
637 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
638 {}
639};
640
Mattc7d4b2f2005-06-27 14:59:41 +0200641static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200642 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200643 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200644 {}
645};
646
Tobin Davis93ed1502006-09-01 21:03:12 +0200647static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200648 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200649 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200650 /* unmute node 0x1b */
651 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
652 /* select node 0x03 as DAC */
653 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
654 {}
655};
656
Matt Porter3cc08dc2006-01-23 15:27:49 +0100657static struct hda_verb stac927x_core_init[] = {
658 /* set master volume and direct control */
659 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
660 {}
661};
662
Matt Porterf3302a52006-07-31 12:49:34 +0200663static struct hda_verb stac9205_core_init[] = {
664 /* set master volume and direct control */
665 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
666 {}
667};
668
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100669#define STAC_MONO_MUX \
670 { \
671 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
672 .name = "Mono Mux", \
673 .count = 1, \
674 .info = stac92xx_mono_mux_enum_info, \
675 .get = stac92xx_mono_mux_enum_get, \
676 .put = stac92xx_mono_mux_enum_put, \
677 }
678
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200679#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200680 { \
681 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
682 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200683 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200684 .info = stac92xx_mux_enum_info, \
685 .get = stac92xx_mux_enum_get, \
686 .put = stac92xx_mux_enum_put, \
687 }
688
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100689#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200690 { \
691 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
692 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100693 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200694 .info = stac92xx_aloopback_info, \
695 .get = stac92xx_aloopback_get, \
696 .put = stac92xx_aloopback_put, \
697 .private_value = verb_read | (verb_write << 16), \
698 }
699
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100700static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200701 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
702 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200703 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200704 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
705 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200706 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200707 { } /* end */
708};
709
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100710static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100711 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
712
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100713 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
714 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
715
716 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
717 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
718
719 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
720 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
721
722 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
723 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
724
725 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
726 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
727
728 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
729 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
730
731 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
732 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
733 { } /* end */
734};
735
736static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100737 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
738
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100739 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
740 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
741
742 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
743 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
744
745 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
746 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
747
748 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
749 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
750
751 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
752 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
753
754 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
755 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
756
757 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
758 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
759 { } /* end */
760};
761
762static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100763 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
764
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100765 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
766 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
767
768 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
769 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
770
771 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
772 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
773
774 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
775 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
776
777 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
778 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
779
780 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
781 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
782
783 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
784 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
785 { } /* end */
786};
787
Matthew Ranostay541eee82007-12-14 12:08:04 +0100788static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100789 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100790
Matthew Ranostay9b359472007-11-07 13:03:12 +0100791 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
792 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
793 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
794
795 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
796 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
797 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
798
799 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
800 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100801 { } /* end */
802};
803
Matthew Ranostay541eee82007-12-14 12:08:04 +0100804static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100805 STAC_INPUT_SOURCE(2),
806 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
807
Matthew Ranostay541eee82007-12-14 12:08:04 +0100808 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
809 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
810 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
811
812 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
813 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
814 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
815 { } /* end */
816};
817
Tobin Davis8e21c342007-01-08 11:04:17 +0100818static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200819 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100820 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
821 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
822 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
823 { } /* end */
824};
825
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100826static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200827 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100828 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200829
830 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
831 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
832 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
833
834 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
835 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
836 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
837
838 { } /* end */
839};
840
841/* This needs to be generated dynamically based on sequence */
842static struct snd_kcontrol_new stac922x_mixer[] = {
843 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200844 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
845 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
846 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
847
848 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
849 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
850 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
851 { } /* end */
852};
853
854
855static struct snd_kcontrol_new stac927x_mixer[] = {
856 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100857 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200858
859 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
860 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
861 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
862
863 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
864 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
865 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
866
867 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
868 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
869 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200870 { } /* end */
871};
872
Takashi Iwai1697055e2007-12-18 18:05:52 +0100873static struct snd_kcontrol_new stac_dmux_mixer = {
874 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
875 .name = "Digital Input Source",
876 /* count set later */
877 .info = stac92xx_dmux_enum_info,
878 .get = stac92xx_dmux_enum_get,
879 .put = stac92xx_dmux_enum_put,
880};
881
Takashi Iwai2134ea42008-01-10 16:53:55 +0100882static const char *slave_vols[] = {
883 "Front Playback Volume",
884 "Surround Playback Volume",
885 "Center Playback Volume",
886 "LFE Playback Volume",
887 "Side Playback Volume",
888 "Headphone Playback Volume",
889 "Headphone Playback Volume",
890 "Speaker Playback Volume",
891 "External Speaker Playback Volume",
892 "Speaker2 Playback Volume",
893 NULL
894};
895
896static const char *slave_sws[] = {
897 "Front Playback Switch",
898 "Surround Playback Switch",
899 "Center Playback Switch",
900 "LFE Playback Switch",
901 "Side Playback Switch",
902 "Headphone Playback Switch",
903 "Headphone Playback Switch",
904 "Speaker Playback Switch",
905 "External Speaker Playback Switch",
906 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100907 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100908 NULL
909};
910
Matt2f2f4252005-04-13 14:45:30 +0200911static int stac92xx_build_controls(struct hda_codec *codec)
912{
913 struct sigmatel_spec *spec = codec->spec;
914 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200915 int i;
Matt2f2f4252005-04-13 14:45:30 +0200916
917 err = snd_hda_add_new_ctls(codec, spec->mixer);
918 if (err < 0)
919 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200920
921 for (i = 0; i < spec->num_mixers; i++) {
922 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
923 if (err < 0)
924 return err;
925 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100926 if (spec->num_dmuxes > 0) {
927 stac_dmux_mixer.count = spec->num_dmuxes;
928 err = snd_ctl_add(codec->bus->card,
929 snd_ctl_new1(&stac_dmux_mixer, codec));
930 if (err < 0)
931 return err;
932 }
Mattc7d4b2f2005-06-27 14:59:41 +0200933
Mattdabbed62005-06-14 10:19:34 +0200934 if (spec->multiout.dig_out_nid) {
935 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
936 if (err < 0)
937 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100938 err = snd_hda_create_spdif_share_sw(codec,
939 &spec->multiout);
940 if (err < 0)
941 return err;
942 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200943 }
944 if (spec->dig_in_nid) {
945 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
946 if (err < 0)
947 return err;
948 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100949
950 /* if we have no master control, let's create it */
951 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100952 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100953 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100954 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100955 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100956 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100957 if (err < 0)
958 return err;
959 }
960 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
961 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
962 NULL, slave_sws);
963 if (err < 0)
964 return err;
965 }
966
Mattdabbed62005-06-14 10:19:34 +0200967 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200968}
969
Matt Porter403d1942005-11-29 15:00:51 +0100970static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200971 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200972 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
973};
974
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200975/*
976 STAC 9200 pin configs for
977 102801A8
978 102801DE
979 102801E8
980*/
981static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200982 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
983 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200984};
985
986/*
987 STAC 9200 pin configs for
988 102801C0
989 102801C1
990*/
991static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200992 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
993 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200994};
995
996/*
997 STAC 9200 pin configs for
998 102801C4 (Dell Dimension E310)
999 102801C5
1000 102801C7
1001 102801D9
1002 102801DA
1003 102801E3
1004*/
1005static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001006 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1007 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001008};
1009
1010
1011/*
1012 STAC 9200-32 pin configs for
1013 102801B5 (Dell Inspiron 630m)
1014 102801D8 (Dell Inspiron 640m)
1015*/
1016static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001017 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1018 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001019};
1020
1021/*
1022 STAC 9200-32 pin configs for
1023 102801C2 (Dell Latitude D620)
1024 102801C8
1025 102801CC (Dell Latitude D820)
1026 102801D4
1027 102801D6
1028*/
1029static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001030 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1031 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001032};
1033
1034/*
1035 STAC 9200-32 pin configs for
1036 102801CE (Dell XPS M1710)
1037 102801CF (Dell Precision M90)
1038*/
1039static unsigned int dell9200_m23_pin_configs[8] = {
1040 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1041 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1042};
1043
1044/*
1045 STAC 9200-32 pin configs for
1046 102801C9
1047 102801CA
1048 102801CB (Dell Latitude 120L)
1049 102801D3
1050*/
1051static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001052 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1053 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001054};
1055
1056/*
1057 STAC 9200-32 pin configs for
1058 102801BD (Dell Inspiron E1505n)
1059 102801EE
1060 102801EF
1061*/
1062static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001063 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1064 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001065};
1066
1067/*
1068 STAC 9200-32 pin configs for
1069 102801F5 (Dell Inspiron 1501)
1070 102801F6
1071*/
1072static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001073 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1074 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001075};
1076
1077/*
1078 STAC 9200-32
1079 102801CD (Dell Inspiron E1705/9400)
1080*/
1081static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001082 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1083 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001084};
1085
Tobin Davisbf277782008-02-03 20:31:47 +01001086static unsigned int oqo9200_pin_configs[8] = {
1087 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1088 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1089};
1090
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001091
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001092static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1093 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001094 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001095 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1096 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1097 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1098 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1099 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1100 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1101 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1102 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1103 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1104 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001105};
1106
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001107static const char *stac9200_models[STAC_9200_MODELS] = {
1108 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001109 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001110 [STAC_9200_DELL_D21] = "dell-d21",
1111 [STAC_9200_DELL_D22] = "dell-d22",
1112 [STAC_9200_DELL_D23] = "dell-d23",
1113 [STAC_9200_DELL_M21] = "dell-m21",
1114 [STAC_9200_DELL_M22] = "dell-m22",
1115 [STAC_9200_DELL_M23] = "dell-m23",
1116 [STAC_9200_DELL_M24] = "dell-m24",
1117 [STAC_9200_DELL_M25] = "dell-m25",
1118 [STAC_9200_DELL_M26] = "dell-m26",
1119 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001120 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001121};
1122
1123static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1124 /* SigmaTel reference board */
1125 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1126 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001127 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001128 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1129 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001130 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001131 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1132 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1133 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1134 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1135 "unknown Dell", STAC_9200_DELL_D22),
1136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1137 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001139 "Dell Latitude D620", STAC_9200_DELL_M22),
1140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1141 "unknown Dell", STAC_9200_DELL_D23),
1142 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1143 "unknown Dell", STAC_9200_DELL_D23),
1144 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1145 "unknown Dell", STAC_9200_DELL_M22),
1146 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1147 "unknown Dell", STAC_9200_DELL_M24),
1148 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1149 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001150 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001151 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001153 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001154 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001155 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001156 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001157 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001158 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001159 "Dell Precision M90", STAC_9200_DELL_M23),
1160 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1161 "unknown Dell", STAC_9200_DELL_M22),
1162 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1163 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001164 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001165 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001166 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001167 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1168 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1169 "unknown Dell", STAC_9200_DELL_D23),
1170 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1171 "unknown Dell", STAC_9200_DELL_D23),
1172 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1173 "unknown Dell", STAC_9200_DELL_D21),
1174 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1175 "unknown Dell", STAC_9200_DELL_D23),
1176 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1177 "unknown Dell", STAC_9200_DELL_D21),
1178 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1179 "unknown Dell", STAC_9200_DELL_M25),
1180 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1181 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001182 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001183 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1184 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1185 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001186 /* Panasonic */
1187 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001188 /* Gateway machines needs EAPD to be set on resume */
1189 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1190 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1191 STAC_9200_GATEWAY),
1192 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1193 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001194 /* OQO Mobile */
1195 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001196 {} /* terminator */
1197};
1198
Tobin Davis8e21c342007-01-08 11:04:17 +01001199static unsigned int ref925x_pin_configs[8] = {
1200 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001201 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001202};
1203
1204static unsigned int stac925x_MA6_pin_configs[8] = {
1205 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1206 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1207};
1208
Tobin Davis2c11f952007-05-17 09:36:34 +02001209static unsigned int stac925x_PA6_pin_configs[8] = {
1210 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1211 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1212};
1213
Tobin Davis8e21c342007-01-08 11:04:17 +01001214static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001215 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1216 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001217};
1218
1219static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1220 [STAC_REF] = ref925x_pin_configs,
1221 [STAC_M2_2] = stac925xM2_2_pin_configs,
1222 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001223 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001224};
1225
1226static const char *stac925x_models[STAC_925x_MODELS] = {
1227 [STAC_REF] = "ref",
1228 [STAC_M2_2] = "m2-2",
1229 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001230 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001231};
1232
1233static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1234 /* SigmaTel reference board */
1235 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001236 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001237 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1238 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1239 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001240 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001241 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1242 {} /* terminator */
1243};
1244
Matthew Ranostaya7662642008-02-21 07:51:14 +01001245static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001246 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1247 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1248 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001249 0x01452050,
1250};
1251
1252static unsigned int dell_m6_pin_configs[13] = {
1253 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
1254 0x03a11020, 0x03011050, 0x4f0000f0, 0x4f0000f0,
1255 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1256 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001257};
1258
1259static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001260 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1261 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001262};
1263
1264static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1265 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001266 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001267};
1268
1269static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1270 /* SigmaTel reference board */
1271 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001272 "DFI LanParty", STAC_92HD73XX_REF),
1273 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1274 "unknown Dell", STAC_DELL_M6),
1275 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1276 "unknown Dell", STAC_DELL_M6),
1277 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1278 "unknown Dell", STAC_DELL_M6),
1279 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1280 "unknown Dell", STAC_DELL_M6),
1281 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1282 "unknown Dell", STAC_DELL_M6),
1283 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1284 "unknown Dell", STAC_DELL_M6),
1285 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1286 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001287 {} /* terminator */
1288};
1289
Matthew Ranostaye035b842007-11-06 11:53:55 +01001290static unsigned int ref92hd71bxx_pin_configs[10] = {
1291 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001292 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001293 0x90a000f0, 0x01452050,
1294};
1295
Matthew Ranostaya7662642008-02-21 07:51:14 +01001296static unsigned int dell_m4_1_pin_configs[13] = {
1297 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
1298 0x23a1902e, 0x23014250, 0x40f000f0, 0x4f0000f0,
1299 0x40f000f0, 0x4f0000f0,
1300};
1301
1302static unsigned int dell_m4_2_pin_configs[13] = {
1303 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1304 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1305 0x40f000f0, 0x044413b0,
1306};
1307
Matthew Ranostaye035b842007-11-06 11:53:55 +01001308static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1309 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001310 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1311 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001312};
1313
1314static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1315 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001316 [STAC_DELL_M4_1] = "dell-m4-1",
1317 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001318};
1319
1320static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1321 /* SigmaTel reference board */
1322 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1323 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001324 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1325 "unknown Dell", STAC_DELL_M4_1),
1326 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1327 "unknown Dell", STAC_DELL_M4_1),
1328 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1329 "unknown Dell", STAC_DELL_M4_1),
1330 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1331 "unknown Dell", STAC_DELL_M4_1),
1332 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1333 "unknown Dell", STAC_DELL_M4_1),
1334 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1335 "unknown Dell", STAC_DELL_M4_1),
1336 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1337 "unknown Dell", STAC_DELL_M4_1),
1338 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1339 "unknown Dell", STAC_DELL_M4_2),
1340 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1341 "unknown Dell", STAC_DELL_M4_2),
1342 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1343 "unknown Dell", STAC_DELL_M4_2),
1344 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1345 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001346 {} /* terminator */
1347};
1348
Matt Porter403d1942005-11-29 15:00:51 +01001349static unsigned int ref922x_pin_configs[10] = {
1350 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1351 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001352 0x40000100, 0x40000100,
1353};
1354
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001355/*
1356 STAC 922X pin configs for
1357 102801A7
1358 102801AB
1359 102801A9
1360 102801D1
1361 102801D2
1362*/
1363static unsigned int dell_922x_d81_pin_configs[10] = {
1364 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1365 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1366 0x01813122, 0x400001f2,
1367};
1368
1369/*
1370 STAC 922X pin configs for
1371 102801AC
1372 102801D0
1373*/
1374static unsigned int dell_922x_d82_pin_configs[10] = {
1375 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1376 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1377 0x01813122, 0x400001f1,
1378};
1379
1380/*
1381 STAC 922X pin configs for
1382 102801BF
1383*/
1384static unsigned int dell_922x_m81_pin_configs[10] = {
1385 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1386 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1387 0x40C003f1, 0x405003f0,
1388};
1389
1390/*
1391 STAC 9221 A1 pin configs for
1392 102801D7 (Dell XPS M1210)
1393*/
1394static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001395 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1396 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001397 0x508003f3, 0x405003f4,
1398};
1399
Matt Porter403d1942005-11-29 15:00:51 +01001400static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001401 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001402 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1403 0x02a19120, 0x40000100,
1404};
1405
1406static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001407 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1408 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001409 0x02a19320, 0x40000100,
1410};
1411
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001412static unsigned int intel_mac_v1_pin_configs[10] = {
1413 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1414 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001415 0x400000fc, 0x400000fb,
1416};
1417
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001418static unsigned int intel_mac_v2_pin_configs[10] = {
1419 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1420 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001421 0x400000fc, 0x400000fb,
1422};
1423
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001424static unsigned int intel_mac_v3_pin_configs[10] = {
1425 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1426 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1427 0x400000fc, 0x400000fb,
1428};
1429
1430static unsigned int intel_mac_v4_pin_configs[10] = {
1431 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1432 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1433 0x400000fc, 0x400000fb,
1434};
1435
1436static unsigned int intel_mac_v5_pin_configs[10] = {
1437 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1438 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1439 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001440};
1441
Takashi Iwai76c08822007-06-19 12:17:42 +02001442
Takashi Iwai19039bd2006-06-28 15:52:16 +02001443static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001444 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001445 [STAC_D945GTP3] = d945gtp3_pin_configs,
1446 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001447 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1448 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1449 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1450 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1451 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001452 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001453 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1454 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1455 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1456 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1457 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1458 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001459 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1460 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1461 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1462 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001463};
1464
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001465static const char *stac922x_models[STAC_922X_MODELS] = {
1466 [STAC_D945_REF] = "ref",
1467 [STAC_D945GTP5] = "5stack",
1468 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001469 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1470 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1471 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1472 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1473 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001474 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001475 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001476 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001477 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1478 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001479 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001480 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001481 [STAC_922X_DELL_D81] = "dell-d81",
1482 [STAC_922X_DELL_D82] = "dell-d82",
1483 [STAC_922X_DELL_M81] = "dell-m81",
1484 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001485};
1486
1487static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1488 /* SigmaTel reference board */
1489 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1490 "DFI LanParty", STAC_D945_REF),
1491 /* Intel 945G based systems */
1492 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1493 "Intel D945G", STAC_D945GTP3),
1494 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1495 "Intel D945G", STAC_D945GTP3),
1496 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1497 "Intel D945G", STAC_D945GTP3),
1498 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1499 "Intel D945G", STAC_D945GTP3),
1500 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1501 "Intel D945G", STAC_D945GTP3),
1502 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1503 "Intel D945G", STAC_D945GTP3),
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1505 "Intel D945G", STAC_D945GTP3),
1506 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1507 "Intel D945G", STAC_D945GTP3),
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1509 "Intel D945G", STAC_D945GTP3),
1510 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1511 "Intel D945G", STAC_D945GTP3),
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1513 "Intel D945G", STAC_D945GTP3),
1514 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1515 "Intel D945G", STAC_D945GTP3),
1516 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1517 "Intel D945G", STAC_D945GTP3),
1518 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1519 "Intel D945G", STAC_D945GTP3),
1520 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1521 "Intel D945G", STAC_D945GTP3),
1522 /* Intel D945G 5-stack systems */
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1524 "Intel D945G", STAC_D945GTP5),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1526 "Intel D945G", STAC_D945GTP5),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1528 "Intel D945G", STAC_D945GTP5),
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1530 "Intel D945G", STAC_D945GTP5),
1531 /* Intel 945P based systems */
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1533 "Intel D945P", STAC_D945GTP3),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1535 "Intel D945P", STAC_D945GTP3),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1537 "Intel D945P", STAC_D945GTP3),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1539 "Intel D945P", STAC_D945GTP3),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1541 "Intel D945P", STAC_D945GTP3),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1543 "Intel D945P", STAC_D945GTP5),
1544 /* other systems */
1545 /* Apple Mac Mini (early 2006) */
1546 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001547 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001548 /* Dell systems */
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1550 "unknown Dell", STAC_922X_DELL_D81),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1552 "unknown Dell", STAC_922X_DELL_D81),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1554 "unknown Dell", STAC_922X_DELL_D81),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1556 "unknown Dell", STAC_922X_DELL_D82),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1558 "unknown Dell", STAC_922X_DELL_M81),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1560 "unknown Dell", STAC_922X_DELL_D82),
1561 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1562 "unknown Dell", STAC_922X_DELL_D81),
1563 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1564 "unknown Dell", STAC_922X_DELL_D81),
1565 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1566 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001567 {} /* terminator */
1568};
1569
Matt Porter3cc08dc2006-01-23 15:27:49 +01001570static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001571 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1572 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1573 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1574 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001575};
1576
Tobin Davis93ed1502006-09-01 21:03:12 +02001577static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001578 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1579 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1580 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1581 0x40000100, 0x40000100
1582};
1583
Tobin Davis93ed1502006-09-01 21:03:12 +02001584static unsigned int d965_5st_pin_configs[14] = {
1585 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1586 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1587 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1588 0x40000100, 0x40000100
1589};
1590
Tobin Davis4ff076e2007-08-07 11:48:12 +02001591static unsigned int dell_3st_pin_configs[14] = {
1592 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1593 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001594 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001595 0x40c003fc, 0x40000100
1596};
1597
Tobin Davis93ed1502006-09-01 21:03:12 +02001598static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001599 [STAC_D965_REF] = ref927x_pin_configs,
1600 [STAC_D965_3ST] = d965_3st_pin_configs,
1601 [STAC_D965_5ST] = d965_5st_pin_configs,
1602 [STAC_DELL_3ST] = dell_3st_pin_configs,
1603 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001604};
1605
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001606static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001607 [STAC_D965_REF] = "ref",
1608 [STAC_D965_3ST] = "3stack",
1609 [STAC_D965_5ST] = "5stack",
1610 [STAC_DELL_3ST] = "dell-3stack",
1611 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001612};
1613
1614static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1615 /* SigmaTel reference board */
1616 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1617 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001618 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001619 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1620 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001621 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001622 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1623 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1624 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1625 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1626 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1627 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1628 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1629 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1630 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1631 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1632 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1633 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1634 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1635 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1636 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1637 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001638 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001639 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001640 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001641 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001643 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001644 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1649 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1650 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001652 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001653 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1654 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1656 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1657 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1658 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1659 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1660 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1661 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001662 {} /* terminator */
1663};
1664
Matt Porterf3302a52006-07-31 12:49:34 +02001665static unsigned int ref9205_pin_configs[12] = {
1666 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001667 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001668 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001669};
1670
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001671/*
1672 STAC 9205 pin configs for
1673 102801F1
1674 102801F2
1675 102801FC
1676 102801FD
1677 10280204
1678 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001679 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001680*/
1681static unsigned int dell_9205_m42_pin_configs[12] = {
1682 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1683 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1684 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1685};
1686
1687/*
1688 STAC 9205 pin configs for
1689 102801F9
1690 102801FA
1691 102801FE
1692 102801FF (Dell Precision M4300)
1693 10280206
1694 10280200
1695 10280201
1696*/
1697static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001698 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1699 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1700 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1701};
1702
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001703static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001704 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1705 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1706 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1707};
1708
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001709static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001710 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001711 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1712 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1713 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001714};
1715
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001716static const char *stac9205_models[STAC_9205_MODELS] = {
1717 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001718 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001719 [STAC_9205_DELL_M43] = "dell-m43",
1720 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001721};
1722
1723static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1724 /* SigmaTel reference board */
1725 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1726 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001727 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1728 "unknown Dell", STAC_9205_DELL_M42),
1729 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1730 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001731 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001732 "Dell Precision", STAC_9205_DELL_M43),
1733 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1734 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001735 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1736 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001737 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1738 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001739 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1740 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001741 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1742 "unknown Dell", STAC_9205_DELL_M42),
1743 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1744 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001745 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1746 "Dell Precision", STAC_9205_DELL_M43),
1747 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001748 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001749 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1750 "Dell Precision", STAC_9205_DELL_M43),
1751 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1752 "Dell Inspiron", STAC_9205_DELL_M44),
1753 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1754 "Dell Inspiron", STAC_9205_DELL_M44),
1755 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1756 "Dell Inspiron", STAC_9205_DELL_M44),
1757 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1758 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001759 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1760 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001761 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1762 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001763 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1764 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001765 {} /* terminator */
1766};
1767
Richard Fish11b44bb2006-08-23 18:31:34 +02001768static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1769{
1770 int i;
1771 struct sigmatel_spec *spec = codec->spec;
1772
1773 if (! spec->bios_pin_configs) {
1774 spec->bios_pin_configs = kcalloc(spec->num_pins,
1775 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1776 if (! spec->bios_pin_configs)
1777 return -ENOMEM;
1778 }
1779
1780 for (i = 0; i < spec->num_pins; i++) {
1781 hda_nid_t nid = spec->pin_nids[i];
1782 unsigned int pin_cfg;
1783
1784 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1785 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1786 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1787 nid, pin_cfg);
1788 spec->bios_pin_configs[i] = pin_cfg;
1789 }
1790
1791 return 0;
1792}
1793
Matthew Ranostay87d48362007-07-17 11:52:24 +02001794static void stac92xx_set_config_reg(struct hda_codec *codec,
1795 hda_nid_t pin_nid, unsigned int pin_config)
1796{
1797 int i;
1798 snd_hda_codec_write(codec, pin_nid, 0,
1799 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1800 pin_config & 0x000000ff);
1801 snd_hda_codec_write(codec, pin_nid, 0,
1802 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1803 (pin_config & 0x0000ff00) >> 8);
1804 snd_hda_codec_write(codec, pin_nid, 0,
1805 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1806 (pin_config & 0x00ff0000) >> 16);
1807 snd_hda_codec_write(codec, pin_nid, 0,
1808 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1809 pin_config >> 24);
1810 i = snd_hda_codec_read(codec, pin_nid, 0,
1811 AC_VERB_GET_CONFIG_DEFAULT,
1812 0x00);
1813 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1814 pin_nid, i);
1815}
1816
Matt2f2f4252005-04-13 14:45:30 +02001817static void stac92xx_set_config_regs(struct hda_codec *codec)
1818{
1819 int i;
1820 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001821
Matthew Ranostay87d48362007-07-17 11:52:24 +02001822 if (!spec->pin_configs)
1823 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001824
Matthew Ranostay87d48362007-07-17 11:52:24 +02001825 for (i = 0; i < spec->num_pins; i++)
1826 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1827 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001828}
Matt2f2f4252005-04-13 14:45:30 +02001829
Matt2f2f4252005-04-13 14:45:30 +02001830/*
1831 * Analog playback callbacks
1832 */
1833static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1834 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001835 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001836{
1837 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001838 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1839 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001840}
1841
1842static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1843 struct hda_codec *codec,
1844 unsigned int stream_tag,
1845 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001846 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001847{
1848 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001849 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001850}
1851
1852static int stac92xx_playback_pcm_cleanup(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;
1857 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1858}
1859
1860/*
Mattdabbed62005-06-14 10:19:34 +02001861 * Digital playback callbacks
1862 */
1863static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1864 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001865 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001866{
1867 struct sigmatel_spec *spec = codec->spec;
1868 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1869}
1870
1871static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1872 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001873 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001874{
1875 struct sigmatel_spec *spec = codec->spec;
1876 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1877}
1878
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001879static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1880 struct hda_codec *codec,
1881 unsigned int stream_tag,
1882 unsigned int format,
1883 struct snd_pcm_substream *substream)
1884{
1885 struct sigmatel_spec *spec = codec->spec;
1886 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1887 stream_tag, format, substream);
1888}
1889
Mattdabbed62005-06-14 10:19:34 +02001890
1891/*
Matt2f2f4252005-04-13 14:45:30 +02001892 * Analog capture callbacks
1893 */
1894static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1895 struct hda_codec *codec,
1896 unsigned int stream_tag,
1897 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001898 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001899{
1900 struct sigmatel_spec *spec = codec->spec;
1901
1902 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1903 stream_tag, 0, format);
1904 return 0;
1905}
1906
1907static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1908 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001909 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001910{
1911 struct sigmatel_spec *spec = codec->spec;
1912
1913 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1914 return 0;
1915}
1916
Mattdabbed62005-06-14 10:19:34 +02001917static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1918 .substreams = 1,
1919 .channels_min = 2,
1920 .channels_max = 2,
1921 /* NID is set in stac92xx_build_pcms */
1922 .ops = {
1923 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001924 .close = stac92xx_dig_playback_pcm_close,
1925 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001926 },
1927};
1928
1929static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1930 .substreams = 1,
1931 .channels_min = 2,
1932 .channels_max = 2,
1933 /* NID is set in stac92xx_build_pcms */
1934};
1935
Matt2f2f4252005-04-13 14:45:30 +02001936static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1937 .substreams = 1,
1938 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001939 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001940 .nid = 0x02, /* NID to query formats and rates */
1941 .ops = {
1942 .open = stac92xx_playback_pcm_open,
1943 .prepare = stac92xx_playback_pcm_prepare,
1944 .cleanup = stac92xx_playback_pcm_cleanup
1945 },
1946};
1947
Matt Porter3cc08dc2006-01-23 15:27:49 +01001948static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1949 .substreams = 1,
1950 .channels_min = 2,
1951 .channels_max = 2,
1952 .nid = 0x06, /* NID to query formats and rates */
1953 .ops = {
1954 .open = stac92xx_playback_pcm_open,
1955 .prepare = stac92xx_playback_pcm_prepare,
1956 .cleanup = stac92xx_playback_pcm_cleanup
1957 },
1958};
1959
Matt2f2f4252005-04-13 14:45:30 +02001960static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001961 .channels_min = 2,
1962 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001963 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001964 .ops = {
1965 .prepare = stac92xx_capture_pcm_prepare,
1966 .cleanup = stac92xx_capture_pcm_cleanup
1967 },
1968};
1969
1970static int stac92xx_build_pcms(struct hda_codec *codec)
1971{
1972 struct sigmatel_spec *spec = codec->spec;
1973 struct hda_pcm *info = spec->pcm_rec;
1974
1975 codec->num_pcms = 1;
1976 codec->pcm_info = info;
1977
Mattc7d4b2f2005-06-27 14:59:41 +02001978 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001979 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001980 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001981 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001982 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001983
1984 if (spec->alt_switch) {
1985 codec->num_pcms++;
1986 info++;
1987 info->name = "STAC92xx Analog Alt";
1988 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1989 }
Matt2f2f4252005-04-13 14:45:30 +02001990
Mattdabbed62005-06-14 10:19:34 +02001991 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1992 codec->num_pcms++;
1993 info++;
1994 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001995 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02001996 if (spec->multiout.dig_out_nid) {
1997 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1998 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1999 }
2000 if (spec->dig_in_nid) {
2001 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2002 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2003 }
2004 }
2005
Matt2f2f4252005-04-13 14:45:30 +02002006 return 0;
2007}
2008
Takashi Iwaic960a032006-03-23 17:06:28 +01002009static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2010{
2011 unsigned int pincap = snd_hda_param_read(codec, nid,
2012 AC_PAR_PIN_CAP);
2013 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2014 if (pincap & AC_PINCAP_VREF_100)
2015 return AC_PINCTL_VREF_100;
2016 if (pincap & AC_PINCAP_VREF_80)
2017 return AC_PINCTL_VREF_80;
2018 if (pincap & AC_PINCAP_VREF_50)
2019 return AC_PINCTL_VREF_50;
2020 if (pincap & AC_PINCAP_VREF_GRD)
2021 return AC_PINCTL_VREF_GRD;
2022 return 0;
2023}
2024
Matt Porter403d1942005-11-29 15:00:51 +01002025static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2026
2027{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002028 snd_hda_codec_write_cache(codec, nid, 0,
2029 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002030}
2031
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002032#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002033
2034static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2035{
2036 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2037 struct sigmatel_spec *spec = codec->spec;
2038 int io_idx = kcontrol-> private_value & 0xff;
2039
2040 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2041 return 0;
2042}
2043
2044static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2045{
2046 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2047 struct sigmatel_spec *spec = codec->spec;
2048 hda_nid_t nid = kcontrol->private_value >> 8;
2049 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002050 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002051
2052 spec->io_switch[io_idx] = val;
2053
2054 if (val)
2055 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002056 else {
2057 unsigned int pinctl = AC_PINCTL_IN_EN;
2058 if (io_idx) /* set VREF for mic */
2059 pinctl |= stac92xx_get_vref(codec, nid);
2060 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2061 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002062
2063 /* check the auto-mute again: we need to mute/unmute the speaker
2064 * appropriately according to the pin direction
2065 */
2066 if (spec->hp_detect)
2067 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2068
Matt Porter403d1942005-11-29 15:00:51 +01002069 return 1;
2070}
2071
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002072#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2073
2074static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2075 struct snd_ctl_elem_value *ucontrol)
2076{
2077 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2078 struct sigmatel_spec *spec = codec->spec;
2079
2080 ucontrol->value.integer.value[0] = spec->clfe_swap;
2081 return 0;
2082}
2083
2084static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2085 struct snd_ctl_elem_value *ucontrol)
2086{
2087 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2088 struct sigmatel_spec *spec = codec->spec;
2089 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002090 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002091
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002092 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002093 return 0;
2094
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002095 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002096
2097 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2098 spec->clfe_swap ? 0x4 : 0x0);
2099
2100 return 1;
2101}
2102
Matt Porter403d1942005-11-29 15:00:51 +01002103#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2104 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2105 .name = xname, \
2106 .index = 0, \
2107 .info = stac92xx_io_switch_info, \
2108 .get = stac92xx_io_switch_get, \
2109 .put = stac92xx_io_switch_put, \
2110 .private_value = xpval, \
2111 }
2112
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002113#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2114 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2115 .name = xname, \
2116 .index = 0, \
2117 .info = stac92xx_clfe_switch_info, \
2118 .get = stac92xx_clfe_switch_get, \
2119 .put = stac92xx_clfe_switch_put, \
2120 .private_value = xpval, \
2121 }
Matt Porter403d1942005-11-29 15:00:51 +01002122
Mattc7d4b2f2005-06-27 14:59:41 +02002123enum {
2124 STAC_CTL_WIDGET_VOL,
2125 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002126 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002127 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002128 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002129};
2130
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002131static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002132 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2133 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002134 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002135 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002136 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002137};
2138
2139/* add dynamic controls */
2140static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2141{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002142 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002143
2144 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2145 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2146
2147 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2148 if (! knew)
2149 return -ENOMEM;
2150 if (spec->kctl_alloc) {
2151 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2152 kfree(spec->kctl_alloc);
2153 }
2154 spec->kctl_alloc = knew;
2155 spec->num_kctl_alloc = num;
2156 }
2157
2158 knew = &spec->kctl_alloc[spec->num_kctl_used];
2159 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002160 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002161 if (! knew->name)
2162 return -ENOMEM;
2163 knew->private_value = val;
2164 spec->num_kctl_used++;
2165 return 0;
2166}
2167
Matt Porter403d1942005-11-29 15:00:51 +01002168/* flag inputs as additional dynamic lineouts */
2169static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2170{
2171 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002172 unsigned int wcaps, wtype;
2173 int i, num_dacs = 0;
2174
2175 /* use the wcaps cache to count all DACs available for line-outs */
2176 for (i = 0; i < codec->num_nodes; i++) {
2177 wcaps = codec->wcaps[i];
2178 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002179
Steve Longerbeam7b043892007-05-03 20:50:03 +02002180 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2181 num_dacs++;
2182 }
Matt Porter403d1942005-11-29 15:00:51 +01002183
Steve Longerbeam7b043892007-05-03 20:50:03 +02002184 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2185
Matt Porter403d1942005-11-29 15:00:51 +01002186 switch (cfg->line_outs) {
2187 case 3:
2188 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002189 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002190 cfg->line_out_pins[cfg->line_outs] =
2191 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002192 spec->line_switch = 1;
2193 cfg->line_outs++;
2194 }
2195 break;
2196 case 2:
2197 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002198 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002199 cfg->line_out_pins[cfg->line_outs] =
2200 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002201 spec->line_switch = 1;
2202 cfg->line_outs++;
2203 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002204 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002205 cfg->line_out_pins[cfg->line_outs] =
2206 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002207 spec->mic_switch = 1;
2208 cfg->line_outs++;
2209 }
2210 break;
2211 case 1:
2212 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002213 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002214 cfg->line_out_pins[cfg->line_outs] =
2215 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002216 spec->line_switch = 1;
2217 cfg->line_outs++;
2218 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002219 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002220 cfg->line_out_pins[cfg->line_outs] =
2221 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002222 spec->mic_switch = 1;
2223 cfg->line_outs++;
2224 }
2225 break;
2226 }
2227
2228 return 0;
2229}
2230
Steve Longerbeam7b043892007-05-03 20:50:03 +02002231
2232static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2233{
2234 int i;
2235
2236 for (i = 0; i < spec->multiout.num_dacs; i++) {
2237 if (spec->multiout.dac_nids[i] == nid)
2238 return 1;
2239 }
2240
2241 return 0;
2242}
2243
Matt Porter3cc08dc2006-01-23 15:27:49 +01002244/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002245 * Fill in the dac_nids table from the parsed pin configuration
2246 * This function only works when every pin in line_out_pins[]
2247 * contains atleast one DAC in its connection list. Some 92xx
2248 * codecs are not connected directly to a DAC, such as the 9200
2249 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002250 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002251static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002252 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002253{
2254 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002255 int i, j, conn_len = 0;
2256 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2257 unsigned int wcaps, wtype;
2258
Mattc7d4b2f2005-06-27 14:59:41 +02002259 for (i = 0; i < cfg->line_outs; i++) {
2260 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002261 conn_len = snd_hda_get_connections(codec, nid, conn,
2262 HDA_MAX_CONNECTIONS);
2263 for (j = 0; j < conn_len; j++) {
2264 wcaps = snd_hda_param_read(codec, conn[j],
2265 AC_PAR_AUDIO_WIDGET_CAP);
2266 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002267 if (wtype != AC_WID_AUD_OUT ||
2268 (wcaps & AC_WCAP_DIGITAL))
2269 continue;
2270 /* conn[j] is a DAC routed to this line-out */
2271 if (!is_in_dac_nids(spec, conn[j]))
2272 break;
2273 }
2274
2275 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002276 if (spec->multiout.num_dacs > 0) {
2277 /* we have already working output pins,
2278 * so let's drop the broken ones again
2279 */
2280 cfg->line_outs = spec->multiout.num_dacs;
2281 break;
2282 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002283 /* error out, no available DAC found */
2284 snd_printk(KERN_ERR
2285 "%s: No available DAC for pin 0x%x\n",
2286 __func__, nid);
2287 return -ENODEV;
2288 }
2289
2290 spec->multiout.dac_nids[i] = conn[j];
2291 spec->multiout.num_dacs++;
2292 if (conn_len > 1) {
2293 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002294 snd_hda_codec_write_cache(codec, nid, 0,
2295 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002296
2297 }
Mattc7d4b2f2005-06-27 14:59:41 +02002298 }
2299
Steve Longerbeam7b043892007-05-03 20:50:03 +02002300 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2301 spec->multiout.num_dacs,
2302 spec->multiout.dac_nids[0],
2303 spec->multiout.dac_nids[1],
2304 spec->multiout.dac_nids[2],
2305 spec->multiout.dac_nids[3],
2306 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002307 return 0;
2308}
2309
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002310/* create volume control/switch for the given prefx type */
2311static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2312{
2313 char name[32];
2314 int err;
2315
2316 sprintf(name, "%s Playback Volume", pfx);
2317 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2318 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2319 if (err < 0)
2320 return err;
2321 sprintf(name, "%s Playback Switch", pfx);
2322 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2323 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2324 if (err < 0)
2325 return err;
2326 return 0;
2327}
2328
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002329static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2330{
2331 if (!spec->multiout.hp_nid)
2332 spec->multiout.hp_nid = nid;
2333 else if (spec->multiout.num_dacs > 4) {
2334 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2335 return 1;
2336 } else {
2337 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2338 spec->multiout.num_dacs++;
2339 }
2340 return 0;
2341}
2342
2343static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2344{
2345 if (is_in_dac_nids(spec, nid))
2346 return 1;
2347 if (spec->multiout.hp_nid == nid)
2348 return 1;
2349 return 0;
2350}
2351
Mattc7d4b2f2005-06-27 14:59:41 +02002352/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002353static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002354 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002355{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002356 static const char *chname[4] = {
2357 "Front", "Surround", NULL /*CLFE*/, "Side"
2358 };
Mattc7d4b2f2005-06-27 14:59:41 +02002359 hda_nid_t nid;
2360 int i, err;
2361
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002362 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002363 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002364
2365
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002366 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002367 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002368 continue;
2369
2370 nid = spec->multiout.dac_nids[i];
2371
2372 if (i == 2) {
2373 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002374 err = create_controls(spec, "Center", nid, 1);
2375 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002376 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002377 err = create_controls(spec, "LFE", nid, 2);
2378 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002379 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002380
2381 wid_caps = get_wcaps(codec, nid);
2382
2383 if (wid_caps & AC_WCAP_LR_SWAP) {
2384 err = stac92xx_add_control(spec,
2385 STAC_CTL_WIDGET_CLFE_SWITCH,
2386 "Swap Center/LFE Playback Switch", nid);
2387
2388 if (err < 0)
2389 return err;
2390 }
2391
Mattc7d4b2f2005-06-27 14:59:41 +02002392 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002393 err = create_controls(spec, chname[i], nid, 3);
2394 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002395 return err;
2396 }
2397 }
2398
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002399 if (spec->line_switch) {
2400 nid = cfg->input_pins[AUTO_PIN_LINE];
2401 pincap = snd_hda_param_read(codec, nid,
2402 AC_PAR_PIN_CAP);
2403 if (pincap & AC_PINCAP_OUT) {
2404 err = stac92xx_add_control(spec,
2405 STAC_CTL_WIDGET_IO_SWITCH,
2406 "Line In as Output Switch", nid << 8);
2407 if (err < 0)
2408 return err;
2409 }
2410 }
Matt Porter403d1942005-11-29 15:00:51 +01002411
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002412 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002413 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002414 unsigned int mic_pin = AUTO_PIN_MIC;
2415again:
2416 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002417 def_conf = snd_hda_codec_read(codec, nid, 0,
2418 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002419 /* some laptops have an internal analog microphone
2420 * which can't be used as a output */
2421 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2422 pincap = snd_hda_param_read(codec, nid,
2423 AC_PAR_PIN_CAP);
2424 if (pincap & AC_PINCAP_OUT) {
2425 err = stac92xx_add_control(spec,
2426 STAC_CTL_WIDGET_IO_SWITCH,
2427 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002428 nid = snd_hda_codec_read(codec, nid, 0,
2429 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2430 if (!check_in_dac_nids(spec, nid))
2431 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002432 if (err < 0)
2433 return err;
2434 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002435 } else if (mic_pin == AUTO_PIN_MIC) {
2436 mic_pin = AUTO_PIN_FRONT_MIC;
2437 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002438 }
2439 }
Matt Porter403d1942005-11-29 15:00:51 +01002440
Mattc7d4b2f2005-06-27 14:59:41 +02002441 return 0;
2442}
2443
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002444/* add playback controls for Speaker and HP outputs */
2445static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2446 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002447{
2448 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002449 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002450 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002451
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002452 old_num_dacs = spec->multiout.num_dacs;
2453 for (i = 0; i < cfg->hp_outs; i++) {
2454 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2455 if (wid_caps & AC_WCAP_UNSOL_CAP)
2456 spec->hp_detect = 1;
2457 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2458 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2459 if (check_in_dac_nids(spec, nid))
2460 nid = 0;
2461 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002462 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002463 add_spec_dacs(spec, nid);
2464 }
2465 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002466 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002467 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2468 if (check_in_dac_nids(spec, nid))
2469 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002470 if (! nid)
2471 continue;
2472 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002473 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002474 for (i = 0; i < cfg->line_outs; i++) {
2475 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2476 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2477 if (check_in_dac_nids(spec, nid))
2478 nid = 0;
2479 if (! nid)
2480 continue;
2481 add_spec_dacs(spec, nid);
2482 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002483 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2484 static const char *pfxs[] = {
2485 "Speaker", "External Speaker", "Speaker2",
2486 };
2487 err = create_controls(spec, pfxs[i - old_num_dacs],
2488 spec->multiout.dac_nids[i], 3);
2489 if (err < 0)
2490 return err;
2491 }
2492 if (spec->multiout.hp_nid) {
2493 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002494 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002495 pfx = "Master";
2496 else
2497 pfx = "Headphone";
2498 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2499 if (err < 0)
2500 return err;
2501 }
Mattc7d4b2f2005-06-27 14:59:41 +02002502
2503 return 0;
2504}
2505
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002506/* labels for mono mux outputs */
2507static const char *stac92xx_mono_labels[3] = {
2508 "DAC0", "DAC1", "Mixer"
2509};
2510
2511/* create mono mux for mono out on capable codecs */
2512static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2513{
2514 struct sigmatel_spec *spec = codec->spec;
2515 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2516 int i, num_cons;
2517 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2518
2519 num_cons = snd_hda_get_connections(codec,
2520 spec->mono_nid,
2521 con_lst,
2522 HDA_MAX_NUM_INPUTS);
2523 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2524 return -EINVAL;
2525
2526 for (i = 0; i < num_cons; i++) {
2527 mono_mux->items[mono_mux->num_items].label =
2528 stac92xx_mono_labels[i];
2529 mono_mux->items[mono_mux->num_items].index = i;
2530 mono_mux->num_items++;
2531 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002532
2533 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2534 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002535}
2536
Matt Porter8b657272006-10-26 17:12:59 +02002537/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002538static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002539 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2540 "Digital Mic 3", "Digital Mic 4"
2541};
2542
2543/* create playback/capture controls for input pins on dmic capable codecs */
2544static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2545 const struct auto_pin_cfg *cfg)
2546{
2547 struct sigmatel_spec *spec = codec->spec;
2548 struct hda_input_mux *dimux = &spec->private_dimux;
2549 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002550 int err, i, j;
2551 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002552
2553 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2554 dimux->items[dimux->num_items].index = 0;
2555 dimux->num_items++;
2556
2557 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002558 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002559 int index;
2560 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002561 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002562 unsigned int def_conf;
2563
2564 def_conf = snd_hda_codec_read(codec,
2565 spec->dmic_nids[i],
2566 0,
2567 AC_VERB_GET_CONFIG_DEFAULT,
2568 0);
2569 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2570 continue;
2571
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002572 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002573 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002574 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002575 con_lst,
2576 HDA_MAX_NUM_INPUTS);
2577 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002578 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002579 index = j;
2580 goto found;
2581 }
2582 continue;
2583found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002584 wcaps = get_wcaps(codec, nid);
2585
2586 if (wcaps & AC_WCAP_OUT_AMP) {
2587 sprintf(name, "%s Capture Volume",
2588 stac92xx_dmic_labels[dimux->num_items]);
2589
2590 err = stac92xx_add_control(spec,
2591 STAC_CTL_WIDGET_VOL,
2592 name,
2593 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2594 if (err < 0)
2595 return err;
2596 }
2597
Matt Porter8b657272006-10-26 17:12:59 +02002598 dimux->items[dimux->num_items].label =
2599 stac92xx_dmic_labels[dimux->num_items];
2600 dimux->items[dimux->num_items].index = index;
2601 dimux->num_items++;
2602 }
2603
2604 return 0;
2605}
2606
Mattc7d4b2f2005-06-27 14:59:41 +02002607/* create playback/capture controls for input pins */
2608static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2609{
2610 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002611 struct hda_input_mux *imux = &spec->private_imux;
2612 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2613 int i, j, k;
2614
2615 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002616 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002617
Takashi Iwai314634b2006-09-21 11:56:18 +02002618 if (!cfg->input_pins[i])
2619 continue;
2620 index = -1;
2621 for (j = 0; j < spec->num_muxes; j++) {
2622 int num_cons;
2623 num_cons = snd_hda_get_connections(codec,
2624 spec->mux_nids[j],
2625 con_lst,
2626 HDA_MAX_NUM_INPUTS);
2627 for (k = 0; k < num_cons; k++)
2628 if (con_lst[k] == cfg->input_pins[i]) {
2629 index = k;
2630 goto found;
2631 }
Mattc7d4b2f2005-06-27 14:59:41 +02002632 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002633 continue;
2634 found:
2635 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2636 imux->items[imux->num_items].index = index;
2637 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002638 }
2639
Steve Longerbeam7b043892007-05-03 20:50:03 +02002640 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002641 /*
2642 * Set the current input for the muxes.
2643 * The STAC9221 has two input muxes with identical source
2644 * NID lists. Hopefully this won't get confused.
2645 */
2646 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002647 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2648 AC_VERB_SET_CONNECT_SEL,
2649 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002650 }
2651 }
2652
Mattc7d4b2f2005-06-27 14:59:41 +02002653 return 0;
2654}
2655
Mattc7d4b2f2005-06-27 14:59:41 +02002656static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2657{
2658 struct sigmatel_spec *spec = codec->spec;
2659 int i;
2660
2661 for (i = 0; i < spec->autocfg.line_outs; i++) {
2662 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2663 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2664 }
2665}
2666
2667static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2668{
2669 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002670 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002671
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002672 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2673 hda_nid_t pin;
2674 pin = spec->autocfg.hp_pins[i];
2675 if (pin) /* connect to front */
2676 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2677 }
2678 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2679 hda_nid_t pin;
2680 pin = spec->autocfg.speaker_pins[i];
2681 if (pin) /* connect to front */
2682 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2683 }
Mattc7d4b2f2005-06-27 14:59:41 +02002684}
2685
Matt Porter3cc08dc2006-01-23 15:27:49 +01002686static 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 +02002687{
2688 struct sigmatel_spec *spec = codec->spec;
2689 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002690 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002691
Matt Porter8b657272006-10-26 17:12:59 +02002692 if ((err = snd_hda_parse_pin_def_config(codec,
2693 &spec->autocfg,
2694 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002695 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002696 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002697 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002698
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002699 /* If we have no real line-out pin and multiple hp-outs, HPs should
2700 * be set up as multi-channel outputs.
2701 */
2702 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2703 spec->autocfg.hp_outs > 1) {
2704 /* Copy hp_outs to line_outs, backup line_outs in
2705 * speaker_outs so that the following routines can handle
2706 * HP pins as primary outputs.
2707 */
2708 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2709 sizeof(spec->autocfg.line_out_pins));
2710 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2711 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2712 sizeof(spec->autocfg.hp_pins));
2713 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2714 hp_speaker_swap = 1;
2715 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002716 if (spec->autocfg.mono_out_pin) {
2717 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2718 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2719 u32 caps = query_amp_caps(codec,
2720 spec->autocfg.mono_out_pin, dir);
2721 hda_nid_t conn_list[1];
2722
2723 /* get the mixer node and then the mono mux if it exists */
2724 if (snd_hda_get_connections(codec,
2725 spec->autocfg.mono_out_pin, conn_list, 1) &&
2726 snd_hda_get_connections(codec, conn_list[0],
2727 conn_list, 1)) {
2728
2729 int wcaps = get_wcaps(codec, conn_list[0]);
2730 int wid_type = (wcaps & AC_WCAP_TYPE)
2731 >> AC_WCAP_TYPE_SHIFT;
2732 /* LR swap check, some stac925x have a mux that
2733 * changes the DACs output path instead of the
2734 * mono-mux path.
2735 */
2736 if (wid_type == AC_WID_AUD_SEL &&
2737 !(wcaps & AC_WCAP_LR_SWAP))
2738 spec->mono_nid = conn_list[0];
2739 }
2740 /* all mono outs have a least a mute/unmute switch */
2741 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2742 "Mono Playback Switch",
2743 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2744 1, 0, dir));
2745 if (err < 0)
2746 return err;
2747 /* check to see if there is volume support for the amp */
2748 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2749 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2750 "Mono Playback Volume",
2751 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2752 1, 0, dir));
2753 if (err < 0)
2754 return err;
2755 }
2756
2757 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2758 AC_PINCTL_OUT_EN);
2759 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002760
Matt Porter403d1942005-11-29 15:00:51 +01002761 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2762 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002763 if (spec->multiout.num_dacs == 0)
2764 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2765 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002766
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002767 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2768
2769 if (err < 0)
2770 return err;
2771
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002772 if (hp_speaker_swap == 1) {
2773 /* Restore the hp_outs and line_outs */
2774 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2775 sizeof(spec->autocfg.line_out_pins));
2776 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2777 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2778 sizeof(spec->autocfg.speaker_pins));
2779 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2780 memset(spec->autocfg.speaker_pins, 0,
2781 sizeof(spec->autocfg.speaker_pins));
2782 spec->autocfg.speaker_outs = 0;
2783 }
2784
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002785 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2786
2787 if (err < 0)
2788 return err;
2789
2790 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2791
2792 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002793 return err;
2794
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002795 if (spec->mono_nid > 0) {
2796 err = stac92xx_auto_create_mono_output_ctls(codec);
2797 if (err < 0)
2798 return err;
2799 }
2800
Matt Porter8b657272006-10-26 17:12:59 +02002801 if (spec->num_dmics > 0)
2802 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2803 &spec->autocfg)) < 0)
2804 return err;
2805
Mattc7d4b2f2005-06-27 14:59:41 +02002806 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002807 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002808 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002809
Takashi Iwai82bc9552006-03-21 11:24:42 +01002810 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002811 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002812 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002813 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002814
2815 if (spec->kctl_alloc)
2816 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2817
2818 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002819 if (!spec->dinput_mux)
2820 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002821 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002822
2823 return 1;
2824}
2825
Takashi Iwai82bc9552006-03-21 11:24:42 +01002826/* add playback controls for HP output */
2827static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2828 struct auto_pin_cfg *cfg)
2829{
2830 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002831 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002832 unsigned int wid_caps;
2833
2834 if (! pin)
2835 return 0;
2836
2837 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002838 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002839 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002840
2841 return 0;
2842}
2843
Richard Fish160ea0d2006-09-06 13:58:25 +02002844/* add playback controls for LFE output */
2845static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2846 struct auto_pin_cfg *cfg)
2847{
2848 struct sigmatel_spec *spec = codec->spec;
2849 int err;
2850 hda_nid_t lfe_pin = 0x0;
2851 int i;
2852
2853 /*
2854 * search speaker outs and line outs for a mono speaker pin
2855 * with an amp. If one is found, add LFE controls
2856 * for it.
2857 */
2858 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2859 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002860 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002861 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2862 if (wcaps == AC_WCAP_OUT_AMP)
2863 /* found a mono speaker with an amp, must be lfe */
2864 lfe_pin = pin;
2865 }
2866
2867 /* if speaker_outs is 0, then speakers may be in line_outs */
2868 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2869 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2870 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002871 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01002872 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02002873 AC_VERB_GET_CONFIG_DEFAULT,
2874 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01002875 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002876 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002877 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2878 if (wcaps == AC_WCAP_OUT_AMP)
2879 /* found a mono speaker with an amp,
2880 must be lfe */
2881 lfe_pin = pin;
2882 }
2883 }
2884 }
2885
2886 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002887 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002888 if (err < 0)
2889 return err;
2890 }
2891
2892 return 0;
2893}
2894
Mattc7d4b2f2005-06-27 14:59:41 +02002895static int stac9200_parse_auto_config(struct hda_codec *codec)
2896{
2897 struct sigmatel_spec *spec = codec->spec;
2898 int err;
2899
Kailang Yangdf694da2005-12-05 19:42:22 +01002900 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002901 return err;
2902
2903 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2904 return err;
2905
Takashi Iwai82bc9552006-03-21 11:24:42 +01002906 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2907 return err;
2908
Richard Fish160ea0d2006-09-06 13:58:25 +02002909 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2910 return err;
2911
Takashi Iwai82bc9552006-03-21 11:24:42 +01002912 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002913 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002914 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002915 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002916
2917 if (spec->kctl_alloc)
2918 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2919
2920 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002921 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002922
2923 return 1;
2924}
2925
Sam Revitch62fe78e2006-05-10 15:09:17 +02002926/*
2927 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2928 * funky external mute control using GPIO pins.
2929 */
2930
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002931static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002932 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002933{
2934 unsigned int gpiostate, gpiomask, gpiodir;
2935
2936 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2937 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002938 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002939
2940 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2941 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002942 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002943
2944 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2945 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002946 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002947
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002948 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002949 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2950
2951 snd_hda_codec_write(codec, codec->afg, 0,
2952 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002953 snd_hda_codec_read(codec, codec->afg, 0,
2954 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002955
2956 msleep(1);
2957
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002958 snd_hda_codec_read(codec, codec->afg, 0,
2959 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002960}
2961
Takashi Iwai314634b2006-09-21 11:56:18 +02002962static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2963 unsigned int event)
2964{
2965 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002966 snd_hda_codec_write_cache(codec, nid, 0,
2967 AC_VERB_SET_UNSOLICITED_ENABLE,
2968 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002969}
2970
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002971static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2972{
2973 int i;
2974 for (i = 0; i < cfg->hp_outs; i++)
2975 if (cfg->hp_pins[i] == nid)
2976 return 1; /* nid is a HP-Out */
2977
2978 return 0; /* nid is not a HP-Out */
2979};
2980
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002981static void stac92xx_power_down(struct hda_codec *codec)
2982{
2983 struct sigmatel_spec *spec = codec->spec;
2984
2985 /* power down inactive DACs */
2986 hda_nid_t *dac;
2987 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01002988 if (!is_in_dac_nids(spec, *dac) &&
2989 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002990 snd_hda_codec_write_cache(codec, *dac, 0,
2991 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
2992}
2993
Mattc7d4b2f2005-06-27 14:59:41 +02002994static int stac92xx_init(struct hda_codec *codec)
2995{
2996 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002997 struct auto_pin_cfg *cfg = &spec->autocfg;
2998 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002999
Mattc7d4b2f2005-06-27 14:59:41 +02003000 snd_hda_sequence_write(codec, spec->init);
3001
Takashi Iwai82bc9552006-03-21 11:24:42 +01003002 /* set up pins */
3003 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003004 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003005 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003006 enable_pin_detect(codec, cfg->hp_pins[i],
3007 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003008 /* force to enable the first line-out; the others are set up
3009 * in unsol_event
3010 */
3011 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3012 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003013 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003014 /* fake event to set up pins */
3015 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3016 } else {
3017 stac92xx_auto_init_multi_out(codec);
3018 stac92xx_auto_init_hp_out(codec);
3019 }
3020 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003021 hda_nid_t nid = cfg->input_pins[i];
3022 if (nid) {
3023 unsigned int pinctl = AC_PINCTL_IN_EN;
3024 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3025 pinctl |= stac92xx_get_vref(codec, nid);
3026 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3027 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003028 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003029 for (i = 0; i < spec->num_dmics; i++)
3030 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3031 AC_PINCTL_IN_EN);
3032 for (i = 0; i < spec->num_pwrs; i++) {
3033 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3034 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3035 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3036 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003037 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3038 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003039 /* outputs are only ports capable of power management
3040 * any attempts on powering down a input port cause the
3041 * referenced VREF to act quirky.
3042 */
3043 if (pinctl & AC_PINCTL_IN_EN)
3044 continue;
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003045 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
3046 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003047 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3048 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3049 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003050 if (spec->dac_list)
3051 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003052 if (cfg->dig_out_pin)
3053 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3054 AC_PINCTL_OUT_EN);
3055 if (cfg->dig_in_pin)
3056 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3057 AC_PINCTL_IN_EN);
3058
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003059 stac_gpio_set(codec, spec->gpio_mask,
3060 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003061
Mattc7d4b2f2005-06-27 14:59:41 +02003062 return 0;
3063}
3064
Matt2f2f4252005-04-13 14:45:30 +02003065static void stac92xx_free(struct hda_codec *codec)
3066{
Mattc7d4b2f2005-06-27 14:59:41 +02003067 struct sigmatel_spec *spec = codec->spec;
3068 int i;
3069
3070 if (! spec)
3071 return;
3072
3073 if (spec->kctl_alloc) {
3074 for (i = 0; i < spec->num_kctl_used; i++)
3075 kfree(spec->kctl_alloc[i].name);
3076 kfree(spec->kctl_alloc);
3077 }
3078
Richard Fish11b44bb2006-08-23 18:31:34 +02003079 if (spec->bios_pin_configs)
3080 kfree(spec->bios_pin_configs);
3081
Mattc7d4b2f2005-06-27 14:59:41 +02003082 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02003083}
3084
Matt4e550962005-07-04 17:51:39 +02003085static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3086 unsigned int flag)
3087{
3088 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3089 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003090
Takashi Iwaif9acba42007-05-29 18:01:06 +02003091 if (pin_ctl & AC_PINCTL_IN_EN) {
3092 /*
3093 * we need to check the current set-up direction of
3094 * shared input pins since they can be switched via
3095 * "xxx as Output" mixer switch
3096 */
3097 struct sigmatel_spec *spec = codec->spec;
3098 struct auto_pin_cfg *cfg = &spec->autocfg;
3099 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3100 spec->line_switch) ||
3101 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3102 spec->mic_switch))
3103 return;
3104 }
3105
Steve Longerbeam7b043892007-05-03 20:50:03 +02003106 /* if setting pin direction bits, clear the current
3107 direction bits first */
3108 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3109 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3110
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003111 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003112 AC_VERB_SET_PIN_WIDGET_CONTROL,
3113 pin_ctl | flag);
3114}
3115
3116static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3117 unsigned int flag)
3118{
3119 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3120 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003121 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003122 AC_VERB_SET_PIN_WIDGET_CONTROL,
3123 pin_ctl & ~flag);
3124}
3125
Jiang Zhe40c1d302007-11-12 13:05:16 +01003126static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003127{
3128 if (!nid)
3129 return 0;
3130 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003131 & (1 << 31)) {
3132 unsigned int pinctl;
3133 pinctl = snd_hda_codec_read(codec, nid, 0,
3134 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3135 if (pinctl & AC_PINCTL_IN_EN)
3136 return 0; /* mic- or line-input */
3137 else
3138 return 1; /* HP-output */
3139 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003140 return 0;
3141}
3142
3143static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003144{
3145 struct sigmatel_spec *spec = codec->spec;
3146 struct auto_pin_cfg *cfg = &spec->autocfg;
3147 int i, presence;
3148
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003149 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003150 if (spec->gpio_mute)
3151 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3152 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3153
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003154 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003155 if (presence)
3156 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003157 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003158 }
Matt4e550962005-07-04 17:51:39 +02003159
3160 if (presence) {
3161 /* disable lineouts, enable hp */
3162 for (i = 0; i < cfg->line_outs; i++)
3163 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3164 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003165 for (i = 0; i < cfg->speaker_outs; i++)
3166 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3167 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003168 } else {
3169 /* enable lineouts, disable hp */
3170 for (i = 0; i < cfg->line_outs; i++)
3171 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3172 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003173 for (i = 0; i < cfg->speaker_outs; i++)
3174 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3175 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003176 }
3177}
3178
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003179static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3180{
3181 struct sigmatel_spec *spec = codec->spec;
3182 hda_nid_t nid = spec->pwr_nids[idx];
3183 int presence, val;
3184 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3185 & 0x000000ff;
3186 presence = get_hp_pin_presence(codec, nid);
3187 idx = 1 << idx;
3188
3189 if (presence)
3190 val &= ~idx;
3191 else
3192 val |= idx;
3193
3194 /* power down unused output ports */
3195 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3196};
3197
Takashi Iwai314634b2006-09-21 11:56:18 +02003198static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3199{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003200 struct sigmatel_spec *spec = codec->spec;
3201 int idx = res >> 26 & 0x0f;
3202
3203 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003204 case STAC_HP_EVENT:
3205 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003206 /* fallthru */
3207 case STAC_PWR_EVENT:
3208 if (spec->num_pwrs > 0)
3209 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003210 }
3211}
3212
Takashi Iwaicb53c622007-08-10 17:21:45 +02003213#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003214static int stac92xx_resume(struct hda_codec *codec)
3215{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003216 struct sigmatel_spec *spec = codec->spec;
3217
Richard Fish11b44bb2006-08-23 18:31:34 +02003218 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003219 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003220 stac_gpio_set(codec, spec->gpio_mask,
3221 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003222 snd_hda_codec_resume_amp(codec);
3223 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003224 /* power down inactive DACs */
3225 if (spec->dac_list)
3226 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003227 /* invoke unsolicited event to reset the HP state */
3228 if (spec->hp_detect)
3229 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003230 return 0;
3231}
3232#endif
3233
Matt2f2f4252005-04-13 14:45:30 +02003234static struct hda_codec_ops stac92xx_patch_ops = {
3235 .build_controls = stac92xx_build_controls,
3236 .build_pcms = stac92xx_build_pcms,
3237 .init = stac92xx_init,
3238 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003239 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003240#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003241 .resume = stac92xx_resume,
3242#endif
Matt2f2f4252005-04-13 14:45:30 +02003243};
3244
3245static int patch_stac9200(struct hda_codec *codec)
3246{
3247 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003248 int err;
Matt2f2f4252005-04-13 14:45:30 +02003249
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003250 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003251 if (spec == NULL)
3252 return -ENOMEM;
3253
3254 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003255 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003256 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003257 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3258 stac9200_models,
3259 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003260 if (spec->board_config < 0) {
3261 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3262 err = stac92xx_save_bios_config_regs(codec);
3263 if (err < 0) {
3264 stac92xx_free(codec);
3265 return err;
3266 }
3267 spec->pin_configs = spec->bios_pin_configs;
3268 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003269 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3270 stac92xx_set_config_regs(codec);
3271 }
Matt2f2f4252005-04-13 14:45:30 +02003272
3273 spec->multiout.max_channels = 2;
3274 spec->multiout.num_dacs = 1;
3275 spec->multiout.dac_nids = stac9200_dac_nids;
3276 spec->adc_nids = stac9200_adc_nids;
3277 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003278 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003279 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003280 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003281 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003282
Tobin Davisbf277782008-02-03 20:31:47 +01003283 if (spec->board_config == STAC_9200_GATEWAY ||
3284 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003285 spec->init = stac9200_eapd_init;
3286 else
3287 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003288 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003289
3290 err = stac9200_parse_auto_config(codec);
3291 if (err < 0) {
3292 stac92xx_free(codec);
3293 return err;
3294 }
Matt2f2f4252005-04-13 14:45:30 +02003295
3296 codec->patch_ops = stac92xx_patch_ops;
3297
3298 return 0;
3299}
3300
Tobin Davis8e21c342007-01-08 11:04:17 +01003301static int patch_stac925x(struct hda_codec *codec)
3302{
3303 struct sigmatel_spec *spec;
3304 int err;
3305
3306 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3307 if (spec == NULL)
3308 return -ENOMEM;
3309
3310 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003311 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003312 spec->pin_nids = stac925x_pin_nids;
3313 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3314 stac925x_models,
3315 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003316 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003317 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003318 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3319 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003320 err = stac92xx_save_bios_config_regs(codec);
3321 if (err < 0) {
3322 stac92xx_free(codec);
3323 return err;
3324 }
3325 spec->pin_configs = spec->bios_pin_configs;
3326 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3327 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3328 stac92xx_set_config_regs(codec);
3329 }
3330
3331 spec->multiout.max_channels = 2;
3332 spec->multiout.num_dacs = 1;
3333 spec->multiout.dac_nids = stac925x_dac_nids;
3334 spec->adc_nids = stac925x_adc_nids;
3335 spec->mux_nids = stac925x_mux_nids;
3336 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003337 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003338 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003339 switch (codec->vendor_id) {
3340 case 0x83847632: /* STAC9202 */
3341 case 0x83847633: /* STAC9202D */
3342 case 0x83847636: /* STAC9251 */
3343 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003344 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003345 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003346 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3347 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003348 break;
3349 default:
3350 spec->num_dmics = 0;
3351 break;
3352 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003353
3354 spec->init = stac925x_core_init;
3355 spec->mixer = stac925x_mixer;
3356
3357 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003358 if (!err) {
3359 if (spec->board_config < 0) {
3360 printk(KERN_WARNING "hda_codec: No auto-config is "
3361 "available, default to model=ref\n");
3362 spec->board_config = STAC_925x_REF;
3363 goto again;
3364 }
3365 err = -EINVAL;
3366 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003367 if (err < 0) {
3368 stac92xx_free(codec);
3369 return err;
3370 }
3371
3372 codec->patch_ops = stac92xx_patch_ops;
3373
3374 return 0;
3375}
3376
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003377static struct hda_input_mux stac92hd73xx_dmux = {
3378 .num_items = 4,
3379 .items = {
3380 { "Analog Inputs", 0x0b },
3381 { "CD", 0x08 },
3382 { "Digital Mic 1", 0x09 },
3383 { "Digital Mic 2", 0x0a },
3384 }
3385};
3386
3387static int patch_stac92hd73xx(struct hda_codec *codec)
3388{
3389 struct sigmatel_spec *spec;
3390 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3391 int err = 0;
3392
3393 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3394 if (spec == NULL)
3395 return -ENOMEM;
3396
3397 codec->spec = spec;
3398 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3399 spec->pin_nids = stac92hd73xx_pin_nids;
3400 spec->board_config = snd_hda_check_board_config(codec,
3401 STAC_92HD73XX_MODELS,
3402 stac92hd73xx_models,
3403 stac92hd73xx_cfg_tbl);
3404again:
3405 if (spec->board_config < 0) {
3406 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3407 " STAC92HD73XX, using BIOS defaults\n");
3408 err = stac92xx_save_bios_config_regs(codec);
3409 if (err < 0) {
3410 stac92xx_free(codec);
3411 return err;
3412 }
3413 spec->pin_configs = spec->bios_pin_configs;
3414 } else {
3415 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3416 stac92xx_set_config_regs(codec);
3417 }
3418
3419 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3420 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3421
3422 if (spec->multiout.num_dacs < 0) {
3423 printk(KERN_WARNING "hda_codec: Could not determine "
3424 "number of channels defaulting to DAC count\n");
3425 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3426 }
3427
3428 switch (spec->multiout.num_dacs) {
3429 case 0x3: /* 6 Channel */
3430 spec->mixer = stac92hd73xx_6ch_mixer;
3431 spec->init = stac92hd73xx_6ch_core_init;
3432 break;
3433 case 0x4: /* 8 Channel */
3434 spec->multiout.hp_nid = 0x18;
3435 spec->mixer = stac92hd73xx_8ch_mixer;
3436 spec->init = stac92hd73xx_8ch_core_init;
3437 break;
3438 case 0x5: /* 10 Channel */
3439 spec->multiout.hp_nid = 0x19;
3440 spec->mixer = stac92hd73xx_10ch_mixer;
3441 spec->init = stac92hd73xx_10ch_core_init;
3442 };
3443
3444 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3445 spec->aloopback_mask = 0x01;
3446 spec->aloopback_shift = 8;
3447
3448 spec->mux_nids = stac92hd73xx_mux_nids;
3449 spec->adc_nids = stac92hd73xx_adc_nids;
3450 spec->dmic_nids = stac92hd73xx_dmic_nids;
3451 spec->dmux_nids = stac92hd73xx_dmux_nids;
3452
3453 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3454 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003455 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003456 spec->dinput_mux = &stac92hd73xx_dmux;
3457 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003458 spec->gpio_mask = spec->gpio_dir = 0x1;
3459 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003460
Matthew Ranostaya7662642008-02-21 07:51:14 +01003461 switch (spec->board_config) {
3462 case STAC_DELL_M6:
Matthew Ranostay52fe0f92008-02-29 12:08:20 +01003463 spec->init = dell_m6_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003464 switch (codec->subsystem_id) {
3465 case 0x1028025e: /* Analog Mics */
3466 case 0x1028025f:
3467 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3468 spec->num_dmics = 0;
3469 break;
3470 case 0x10280254: /* Digital Mics */
3471 case 0x10280255:
3472 case 0x10280271:
3473 case 0x10280272:
3474 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3475 spec->num_dmics = 1;
3476 break;
3477 case 0x10280256: /* Both */
3478 case 0x10280057:
3479 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3480 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3481 spec->num_dmics = 1;
3482 break;
3483 }
3484 break;
3485 default:
3486 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3487 }
3488
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003489 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3490 spec->pwr_nids = stac92hd73xx_pwr_nids;
3491
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003492 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3493
3494 if (!err) {
3495 if (spec->board_config < 0) {
3496 printk(KERN_WARNING "hda_codec: No auto-config is "
3497 "available, default to model=ref\n");
3498 spec->board_config = STAC_92HD73XX_REF;
3499 goto again;
3500 }
3501 err = -EINVAL;
3502 }
3503
3504 if (err < 0) {
3505 stac92xx_free(codec);
3506 return err;
3507 }
3508
3509 codec->patch_ops = stac92xx_patch_ops;
3510
3511 return 0;
3512}
3513
Matthew Ranostaye035b842007-11-06 11:53:55 +01003514static int patch_stac92hd71bxx(struct hda_codec *codec)
3515{
3516 struct sigmatel_spec *spec;
3517 int err = 0;
3518
3519 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3520 if (spec == NULL)
3521 return -ENOMEM;
3522
3523 codec->spec = spec;
3524 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3525 spec->pin_nids = stac92hd71bxx_pin_nids;
3526 spec->board_config = snd_hda_check_board_config(codec,
3527 STAC_92HD71BXX_MODELS,
3528 stac92hd71bxx_models,
3529 stac92hd71bxx_cfg_tbl);
3530again:
3531 if (spec->board_config < 0) {
3532 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3533 " STAC92HD71BXX, using BIOS defaults\n");
3534 err = stac92xx_save_bios_config_regs(codec);
3535 if (err < 0) {
3536 stac92xx_free(codec);
3537 return err;
3538 }
3539 spec->pin_configs = spec->bios_pin_configs;
3540 } else {
3541 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3542 stac92xx_set_config_regs(codec);
3543 }
3544
Matthew Ranostay541eee82007-12-14 12:08:04 +01003545 switch (codec->vendor_id) {
3546 case 0x111d76b6: /* 4 Port without Analog Mixer */
3547 case 0x111d76b7:
3548 case 0x111d76b4: /* 6 Port without Analog Mixer */
3549 case 0x111d76b5:
3550 spec->mixer = stac92hd71bxx_mixer;
3551 spec->init = stac92hd71bxx_core_init;
3552 break;
3553 default:
3554 spec->mixer = stac92hd71bxx_analog_mixer;
3555 spec->init = stac92hd71bxx_analog_core_init;
3556 }
3557
3558 spec->aloopback_mask = 0x20;
3559 spec->aloopback_shift = 0;
3560
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003561 /* GPIO0 High = EAPD */
3562 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003563
Matthew Ranostaye035b842007-11-06 11:53:55 +01003564 spec->mux_nids = stac92hd71bxx_mux_nids;
3565 spec->adc_nids = stac92hd71bxx_adc_nids;
3566 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003567 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003568
3569 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3570 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3571 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003572 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003573
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003574 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3575 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3576
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01003577 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003578 spec->multiout.hp_nid = 0x11;
3579 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3580
3581 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3582 if (!err) {
3583 if (spec->board_config < 0) {
3584 printk(KERN_WARNING "hda_codec: No auto-config is "
3585 "available, default to model=ref\n");
3586 spec->board_config = STAC_92HD71BXX_REF;
3587 goto again;
3588 }
3589 err = -EINVAL;
3590 }
3591
3592 if (err < 0) {
3593 stac92xx_free(codec);
3594 return err;
3595 }
3596
3597 codec->patch_ops = stac92xx_patch_ops;
3598
3599 return 0;
3600};
3601
Matt2f2f4252005-04-13 14:45:30 +02003602static int patch_stac922x(struct hda_codec *codec)
3603{
3604 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003605 int err;
Matt2f2f4252005-04-13 14:45:30 +02003606
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003607 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003608 if (spec == NULL)
3609 return -ENOMEM;
3610
3611 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003612 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003613 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003614 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3615 stac922x_models,
3616 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003617 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003618 spec->gpio_mask = spec->gpio_dir = 0x03;
3619 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003620 /* Intel Macs have all same PCI SSID, so we need to check
3621 * codec SSID to distinguish the exact models
3622 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003623 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003624 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003625
3626 case 0x106b0800:
3627 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003628 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003629 case 0x106b0600:
3630 case 0x106b0700:
3631 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003632 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003633 case 0x106b0e00:
3634 case 0x106b0f00:
3635 case 0x106b1600:
3636 case 0x106b1700:
3637 case 0x106b0200:
3638 case 0x106b1e00:
3639 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003640 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003641 case 0x106b1a00:
3642 case 0x00000100:
3643 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003644 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003645 case 0x106b0a00:
3646 case 0x106b2200:
3647 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003648 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003649 }
3650 }
3651
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003652 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003653 if (spec->board_config < 0) {
3654 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3655 "using BIOS defaults\n");
3656 err = stac92xx_save_bios_config_regs(codec);
3657 if (err < 0) {
3658 stac92xx_free(codec);
3659 return err;
3660 }
3661 spec->pin_configs = spec->bios_pin_configs;
3662 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003663 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3664 stac92xx_set_config_regs(codec);
3665 }
Matt2f2f4252005-04-13 14:45:30 +02003666
Matt2f2f4252005-04-13 14:45:30 +02003667 spec->adc_nids = stac922x_adc_nids;
3668 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003669 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003670 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003671 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003672 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003673
3674 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003675 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003676
3677 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003678
Matt Porter3cc08dc2006-01-23 15:27:49 +01003679 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003680 if (!err) {
3681 if (spec->board_config < 0) {
3682 printk(KERN_WARNING "hda_codec: No auto-config is "
3683 "available, default to model=ref\n");
3684 spec->board_config = STAC_D945_REF;
3685 goto again;
3686 }
3687 err = -EINVAL;
3688 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003689 if (err < 0) {
3690 stac92xx_free(codec);
3691 return err;
3692 }
3693
3694 codec->patch_ops = stac92xx_patch_ops;
3695
Takashi Iwai807a46362007-05-29 19:01:37 +02003696 /* Fix Mux capture level; max to 2 */
3697 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3698 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3699 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3700 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3701 (0 << AC_AMPCAP_MUTE_SHIFT));
3702
Matt Porter3cc08dc2006-01-23 15:27:49 +01003703 return 0;
3704}
3705
3706static int patch_stac927x(struct hda_codec *codec)
3707{
3708 struct sigmatel_spec *spec;
3709 int err;
3710
3711 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3712 if (spec == NULL)
3713 return -ENOMEM;
3714
3715 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003716 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003717 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003718 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3719 stac927x_models,
3720 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003721 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003722 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3723 if (spec->board_config < 0)
3724 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3725 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003726 err = stac92xx_save_bios_config_regs(codec);
3727 if (err < 0) {
3728 stac92xx_free(codec);
3729 return err;
3730 }
3731 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003732 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003733 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3734 stac92xx_set_config_regs(codec);
3735 }
3736
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003737 spec->adc_nids = stac927x_adc_nids;
3738 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3739 spec->mux_nids = stac927x_mux_nids;
3740 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003741 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003742 spec->multiout.dac_nids = spec->dac_nids;
3743
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003744 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003745 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003746 case STAC_D965_5ST:
3747 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003748 spec->gpio_mask = spec->gpio_dir = 0x01;
3749 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003750 spec->num_dmics = 0;
3751
Tobin Davis93ed1502006-09-01 21:03:12 +02003752 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003753 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003754 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003755 case STAC_DELL_BIOS:
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003756 /* configure the analog microphone on some laptops */
3757 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003758 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003759 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003760 /* correct the front input jack as a mic */
3761 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3762 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003763 case STAC_DELL_3ST:
3764 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003765 spec->gpio_mask = spec->gpio_dir = 0x04;
3766 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003767 spec->dmic_nids = stac927x_dmic_nids;
3768 spec->num_dmics = STAC927X_NUM_DMICS;
3769
Tobin Davis93ed1502006-09-01 21:03:12 +02003770 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003771 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003772 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003773 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003774 break;
3775 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003776 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003777 spec->gpio_mask = spec->gpio_dir = 0x1;
3778 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003779 spec->num_dmics = 0;
3780
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003781 spec->init = stac927x_core_init;
3782 spec->mixer = stac927x_mixer;
3783 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003784
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003785 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003786 spec->aloopback_mask = 0x40;
3787 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003788
Matt Porter3cc08dc2006-01-23 15:27:49 +01003789 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003790 if (!err) {
3791 if (spec->board_config < 0) {
3792 printk(KERN_WARNING "hda_codec: No auto-config is "
3793 "available, default to model=ref\n");
3794 spec->board_config = STAC_D965_REF;
3795 goto again;
3796 }
3797 err = -EINVAL;
3798 }
Mattc7d4b2f2005-06-27 14:59:41 +02003799 if (err < 0) {
3800 stac92xx_free(codec);
3801 return err;
3802 }
Matt2f2f4252005-04-13 14:45:30 +02003803
3804 codec->patch_ops = stac92xx_patch_ops;
3805
Takashi Iwai52987652008-01-16 16:09:47 +01003806 /*
3807 * !!FIXME!!
3808 * The STAC927x seem to require fairly long delays for certain
3809 * command sequences. With too short delays (even if the answer
3810 * is set to RIRB properly), it results in the silence output
3811 * on some hardwares like Dell.
3812 *
3813 * The below flag enables the longer delay (see get_response
3814 * in hda_intel.c).
3815 */
3816 codec->bus->needs_damn_long_delay = 1;
3817
Matt2f2f4252005-04-13 14:45:30 +02003818 return 0;
3819}
3820
Matt Porterf3302a52006-07-31 12:49:34 +02003821static int patch_stac9205(struct hda_codec *codec)
3822{
3823 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003824 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003825
3826 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3827 if (spec == NULL)
3828 return -ENOMEM;
3829
3830 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003831 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003832 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003833 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3834 stac9205_models,
3835 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003836 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003837 if (spec->board_config < 0) {
3838 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3839 err = stac92xx_save_bios_config_regs(codec);
3840 if (err < 0) {
3841 stac92xx_free(codec);
3842 return err;
3843 }
3844 spec->pin_configs = spec->bios_pin_configs;
3845 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003846 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3847 stac92xx_set_config_regs(codec);
3848 }
3849
3850 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003851 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003852 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003853 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003854 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003855 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003856 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003857 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003858 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003859
3860 spec->init = stac9205_core_init;
3861 spec->mixer = stac9205_mixer;
3862
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003863 spec->aloopback_mask = 0x40;
3864 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003865 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003866
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003867 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003868 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003869 /* Enable SPDIF in/out */
3870 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3871 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003872
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003873 /* Enable unsol response for GPIO4/Dock HP connection */
3874 snd_hda_codec_write(codec, codec->afg, 0,
3875 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3876 snd_hda_codec_write_cache(codec, codec->afg, 0,
3877 AC_VERB_SET_UNSOLICITED_ENABLE,
3878 (AC_USRSP_EN | STAC_HP_EVENT));
3879
3880 spec->gpio_dir = 0x0b;
3881 spec->gpio_mask = 0x1b;
3882 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003883 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003884 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003885 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003886 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003887 break;
3888 default:
3889 /* GPIO0 High = EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003890 spec->gpio_mask = spec->gpio_dir = 0x1;
3891 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003892 break;
3893 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003894
Matt Porterf3302a52006-07-31 12:49:34 +02003895 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003896 if (!err) {
3897 if (spec->board_config < 0) {
3898 printk(KERN_WARNING "hda_codec: No auto-config is "
3899 "available, default to model=ref\n");
3900 spec->board_config = STAC_9205_REF;
3901 goto again;
3902 }
3903 err = -EINVAL;
3904 }
Matt Porterf3302a52006-07-31 12:49:34 +02003905 if (err < 0) {
3906 stac92xx_free(codec);
3907 return err;
3908 }
3909
3910 codec->patch_ops = stac92xx_patch_ops;
3911
3912 return 0;
3913}
3914
Matt2f2f4252005-04-13 14:45:30 +02003915/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003916 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003917 */
3918
Guillaume Munch99ccc562006-08-16 19:35:12 +02003919/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003920static hda_nid_t vaio_dacs[] = { 0x2 };
3921#define VAIO_HP_DAC 0x5
3922static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3923static hda_nid_t vaio_mux_nids[] = { 0x15 };
3924
3925static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003926 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003927 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003928 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003929 { "Mic Jack", 0x1 },
3930 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003931 { "PCM", 0x3 },
3932 }
3933};
3934
3935static struct hda_verb vaio_init[] = {
3936 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003937 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003938 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3939 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3940 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3941 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003942 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003943 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3944 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3945 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3946 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3947 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3948 {}
3949};
3950
Guillaume Munch6d859062006-08-22 17:15:47 +02003951static struct hda_verb vaio_ar_init[] = {
3952 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3953 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3954 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3955 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3956/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3957 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003958 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003959 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3960 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3961/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
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
Takashi Iwaidb064e52006-03-16 16:04:58 +01003968/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003969static struct hda_bind_ctls vaio_bind_master_vol = {
3970 .ops = &snd_hda_bind_vol,
3971 .values = {
3972 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3973 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3974 0
3975 },
3976};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003977
3978/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003979static struct hda_bind_ctls vaio_bind_master_sw = {
3980 .ops = &snd_hda_bind_sw,
3981 .values = {
3982 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3983 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3984 0,
3985 },
3986};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003987
3988static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003989 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3990 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003991 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3992 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3993 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3994 {
3995 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3996 .name = "Capture Source",
3997 .count = 1,
3998 .info = stac92xx_mux_enum_info,
3999 .get = stac92xx_mux_enum_get,
4000 .put = stac92xx_mux_enum_put,
4001 },
4002 {}
4003};
4004
Guillaume Munch6d859062006-08-22 17:15:47 +02004005static struct snd_kcontrol_new vaio_ar_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),
Guillaume Munch6d859062006-08-22 17:15:47 +02004008 /* 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 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4012 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4013 {
4014 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4015 .name = "Capture Source",
4016 .count = 1,
4017 .info = stac92xx_mux_enum_info,
4018 .get = stac92xx_mux_enum_get,
4019 .put = stac92xx_mux_enum_put,
4020 },
4021 {}
4022};
4023
4024static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004025 .build_controls = stac92xx_build_controls,
4026 .build_pcms = stac92xx_build_pcms,
4027 .init = stac92xx_init,
4028 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004029#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004030 .resume = stac92xx_resume,
4031#endif
4032};
4033
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004034static int stac9872_vaio_init(struct hda_codec *codec)
4035{
4036 int err;
4037
4038 err = stac92xx_init(codec);
4039 if (err < 0)
4040 return err;
4041 if (codec->patch_ops.unsol_event)
4042 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4043 return 0;
4044}
4045
4046static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4047{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004048 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004049 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4050 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4051 } else {
4052 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4053 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4054 }
4055}
4056
4057static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4058{
4059 switch (res >> 26) {
4060 case STAC_HP_EVENT:
4061 stac9872_vaio_hp_detect(codec, res);
4062 break;
4063 }
4064}
4065
4066static struct hda_codec_ops stac9872_vaio_patch_ops = {
4067 .build_controls = stac92xx_build_controls,
4068 .build_pcms = stac92xx_build_pcms,
4069 .init = stac9872_vaio_init,
4070 .free = stac92xx_free,
4071 .unsol_event = stac9872_vaio_unsol_event,
4072#ifdef CONFIG_PM
4073 .resume = stac92xx_resume,
4074#endif
4075};
4076
Guillaume Munch6d859062006-08-22 17:15:47 +02004077enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4078 CXD9872RD_VAIO,
4079 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4080 STAC9872AK_VAIO,
4081 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4082 STAC9872K_VAIO,
4083 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004084 CXD9872AKD_VAIO,
4085 STAC_9872_MODELS,
4086};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004087
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004088static const char *stac9872_models[STAC_9872_MODELS] = {
4089 [CXD9872RD_VAIO] = "vaio",
4090 [CXD9872AKD_VAIO] = "vaio-ar",
4091};
4092
4093static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4094 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4095 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4096 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004097 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004098 {}
4099};
4100
Guillaume Munch6d859062006-08-22 17:15:47 +02004101static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004102{
4103 struct sigmatel_spec *spec;
4104 int board_config;
4105
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004106 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4107 stac9872_models,
4108 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004109 if (board_config < 0)
4110 /* unknown config, let generic-parser do its job... */
4111 return snd_hda_parse_generic_codec(codec);
4112
4113 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4114 if (spec == NULL)
4115 return -ENOMEM;
4116
4117 codec->spec = spec;
4118 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004119 case CXD9872RD_VAIO:
4120 case STAC9872AK_VAIO:
4121 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004122 spec->mixer = vaio_mixer;
4123 spec->init = vaio_init;
4124 spec->multiout.max_channels = 2;
4125 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4126 spec->multiout.dac_nids = vaio_dacs;
4127 spec->multiout.hp_nid = VAIO_HP_DAC;
4128 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4129 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004130 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004131 spec->input_mux = &vaio_mux;
4132 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004133 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004134 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004135
4136 case CXD9872AKD_VAIO:
4137 spec->mixer = vaio_ar_mixer;
4138 spec->init = vaio_ar_init;
4139 spec->multiout.max_channels = 2;
4140 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4141 spec->multiout.dac_nids = vaio_dacs;
4142 spec->multiout.hp_nid = VAIO_HP_DAC;
4143 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004144 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004145 spec->adc_nids = vaio_adcs;
4146 spec->input_mux = &vaio_mux;
4147 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004148 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004149 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004150 }
4151
Takashi Iwaidb064e52006-03-16 16:04:58 +01004152 return 0;
4153}
4154
4155
4156/*
Matt2f2f4252005-04-13 14:45:30 +02004157 * patch entries
4158 */
4159struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4160 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4161 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4162 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4163 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4164 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4165 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4166 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004167 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4168 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4169 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4170 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4171 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4172 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004173 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4174 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4175 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4176 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4177 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4178 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4179 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4180 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4181 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4182 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004183 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4184 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4185 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4186 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4187 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4188 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004189 /* The following does not take into account .id=0x83847661 when subsys =
4190 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4191 * currently not fully supported.
4192 */
4193 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4194 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4195 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004196 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4197 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4198 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4199 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4200 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4201 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4202 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4203 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004204 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4205 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004206 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004207 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4208 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4209 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4210 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4211 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4212 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4213 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4214 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4215 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004216 {} /* terminator */
4217};