blob: 1ef3dd6e8a6436a3c447a5e4c47fc6f2d0125406 [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 Iwai117f2572008-03-18 09:53:23 +010055 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010056 STAC_9200_MODELS
57};
58
59enum {
60 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020061 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020062 STAC_9205_DELL_M43,
63 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010064 STAC_9205_MODELS
65};
66
67enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010068 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010069 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010070 STAC_92HD73XX_MODELS
71};
72
73enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010074 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010075 STAC_DELL_M4_1,
76 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010077 STAC_92HD71BXX_MODELS
78};
79
80enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010081 STAC_925x_REF,
82 STAC_M2_2,
83 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020084 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010085 STAC_925x_MODELS
86};
87
88enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010089 STAC_D945_REF,
90 STAC_D945GTP3,
91 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020092 STAC_INTEL_MAC_V1,
93 STAC_INTEL_MAC_V2,
94 STAC_INTEL_MAC_V3,
95 STAC_INTEL_MAC_V4,
96 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020097 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010098 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010099 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100100 STAC_MACBOOK_PRO_V1,
101 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200102 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200103 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200104 STAC_922X_DELL_D81,
105 STAC_922X_DELL_D82,
106 STAC_922X_DELL_M81,
107 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100108 STAC_922X_MODELS
109};
110
111enum {
112 STAC_D965_REF,
113 STAC_D965_3ST,
114 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200115 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100116 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100117 STAC_927X_MODELS
118};
Matt Porter403d1942005-11-29 15:00:51 +0100119
Matt2f2f4252005-04-13 14:45:30 +0200120struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100121 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200122 unsigned int num_mixers;
123
Matt Porter403d1942005-11-29 15:00:51 +0100124 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200125 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100126 unsigned int line_switch: 1;
127 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100128 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100129 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200130
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100131 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200132 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100133 unsigned int gpio_mask;
134 unsigned int gpio_dir;
135 unsigned int gpio_data;
136 unsigned int gpio_mute;
137
138 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100139 unsigned char aloopback_mask;
140 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200141
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100142 /* power management */
143 unsigned int num_pwrs;
144 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100145 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100146
Matt2f2f4252005-04-13 14:45:30 +0200147 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100148 struct hda_input_mux *mono_mux;
149 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200150 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100151 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200152
153 /* capture */
154 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200155 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200156 hda_nid_t *mux_nids;
157 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200158 hda_nid_t *dmic_nids;
159 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100160 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100161 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200162 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100163 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200164
Matt2f2f4252005-04-13 14:45:30 +0200165 /* pin widgets */
166 hda_nid_t *pin_nids;
167 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200168 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200169 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200170
171 /* codec specific stuff */
172 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100173 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200174
175 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200176 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100177 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200178 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100179 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200180
Matt Porter403d1942005-11-29 15:00:51 +0100181 /* i/o switches */
182 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200183 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200184 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200185 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200186
Mattc7d4b2f2005-06-27 14:59:41 +0200187 struct hda_pcm pcm_rec[2]; /* PCM information */
188
189 /* dynamic controls and input_mux */
190 struct auto_pin_cfg autocfg;
191 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100192 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200193 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200194 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100195 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200196};
197
198static hda_nid_t stac9200_adc_nids[1] = {
199 0x03,
200};
201
202static hda_nid_t stac9200_mux_nids[1] = {
203 0x0c,
204};
205
206static hda_nid_t stac9200_dac_nids[1] = {
207 0x02,
208};
209
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100210static hda_nid_t stac92hd73xx_pwr_nids[8] = {
211 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
212 0x0f, 0x10, 0x11
213};
214
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100215static hda_nid_t stac92hd73xx_adc_nids[2] = {
216 0x1a, 0x1b
217};
218
219#define STAC92HD73XX_NUM_DMICS 2
220static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
221 0x13, 0x14, 0
222};
223
224#define STAC92HD73_DAC_COUNT 5
225static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
226 0x15, 0x16, 0x17, 0x18, 0x19,
227};
228
229static hda_nid_t stac92hd73xx_mux_nids[4] = {
230 0x28, 0x29, 0x2a, 0x2b,
231};
232
233static hda_nid_t stac92hd73xx_dmux_nids[2] = {
234 0x20, 0x21,
235};
236
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100237static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
238 0x0a, 0x0d, 0x0f
239};
240
Matthew Ranostaye035b842007-11-06 11:53:55 +0100241static hda_nid_t stac92hd71bxx_adc_nids[2] = {
242 0x12, 0x13,
243};
244
245static hda_nid_t stac92hd71bxx_mux_nids[2] = {
246 0x1a, 0x1b
247};
248
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100249static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
250 0x1c,
251};
252
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100253static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100254 0x10, /*0x11, */
255};
256
257#define STAC92HD71BXX_NUM_DMICS 2
258static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
259 0x18, 0x19, 0
260};
261
Tobin Davis8e21c342007-01-08 11:04:17 +0100262static hda_nid_t stac925x_adc_nids[1] = {
263 0x03,
264};
265
266static hda_nid_t stac925x_mux_nids[1] = {
267 0x0f,
268};
269
270static hda_nid_t stac925x_dac_nids[1] = {
271 0x02,
272};
273
Takashi Iwaif6e98522007-10-16 14:27:04 +0200274#define STAC925X_NUM_DMICS 1
275static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
276 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200277};
278
Takashi Iwai1697055e2007-12-18 18:05:52 +0100279static hda_nid_t stac925x_dmux_nids[1] = {
280 0x14,
281};
282
Matt2f2f4252005-04-13 14:45:30 +0200283static hda_nid_t stac922x_adc_nids[2] = {
284 0x06, 0x07,
285};
286
287static hda_nid_t stac922x_mux_nids[2] = {
288 0x12, 0x13,
289};
290
Matt Porter3cc08dc2006-01-23 15:27:49 +0100291static hda_nid_t stac927x_adc_nids[3] = {
292 0x07, 0x08, 0x09
293};
294
295static hda_nid_t stac927x_mux_nids[3] = {
296 0x15, 0x16, 0x17
297};
298
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100299static hda_nid_t stac927x_dac_nids[6] = {
300 0x02, 0x03, 0x04, 0x05, 0x06, 0
301};
302
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100303static hda_nid_t stac927x_dmux_nids[1] = {
304 0x1b,
305};
306
Matthew Ranostay7f168592007-10-18 17:38:17 +0200307#define STAC927X_NUM_DMICS 2
308static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
309 0x13, 0x14, 0
310};
311
Matt Porterf3302a52006-07-31 12:49:34 +0200312static hda_nid_t stac9205_adc_nids[2] = {
313 0x12, 0x13
314};
315
316static hda_nid_t stac9205_mux_nids[2] = {
317 0x19, 0x1a
318};
319
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100320static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100321 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100322};
323
Takashi Iwaif6e98522007-10-16 14:27:04 +0200324#define STAC9205_NUM_DMICS 2
325static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
326 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200327};
328
Mattc7d4b2f2005-06-27 14:59:41 +0200329static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200330 0x08, 0x09, 0x0d, 0x0e,
331 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200332};
333
Tobin Davis8e21c342007-01-08 11:04:17 +0100334static hda_nid_t stac925x_pin_nids[8] = {
335 0x07, 0x08, 0x0a, 0x0b,
336 0x0c, 0x0d, 0x10, 0x11,
337};
338
Matt2f2f4252005-04-13 14:45:30 +0200339static hda_nid_t stac922x_pin_nids[10] = {
340 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
341 0x0f, 0x10, 0x11, 0x15, 0x1b,
342};
343
Matthew Ranostaya7662642008-02-21 07:51:14 +0100344static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100345 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
346 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100347 0x14, 0x1e, 0x22
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100348};
349
Matthew Ranostaye035b842007-11-06 11:53:55 +0100350static hda_nid_t stac92hd71bxx_pin_nids[10] = {
351 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
352 0x0f, 0x14, 0x18, 0x19, 0x1e,
353};
354
Matt Porter3cc08dc2006-01-23 15:27:49 +0100355static hda_nid_t stac927x_pin_nids[14] = {
356 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
357 0x0f, 0x10, 0x11, 0x12, 0x13,
358 0x14, 0x21, 0x22, 0x23,
359};
360
Matt Porterf3302a52006-07-31 12:49:34 +0200361static hda_nid_t stac9205_pin_nids[12] = {
362 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
363 0x0f, 0x14, 0x16, 0x17, 0x18,
364 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200365};
366
Matt Porter8b657272006-10-26 17:12:59 +0200367static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
368 struct snd_ctl_elem_info *uinfo)
369{
370 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
371 struct sigmatel_spec *spec = codec->spec;
372 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
373}
374
375static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
376 struct snd_ctl_elem_value *ucontrol)
377{
378 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
379 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100380 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200381
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100382 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200383 return 0;
384}
385
386static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
387 struct snd_ctl_elem_value *ucontrol)
388{
389 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
390 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100391 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200392
393 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100394 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200395}
396
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100397static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200398{
399 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
400 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200401 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200402}
403
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100404static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200405{
406 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
407 struct sigmatel_spec *spec = codec->spec;
408 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
409
410 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
411 return 0;
412}
413
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100414static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200415{
416 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
417 struct sigmatel_spec *spec = codec->spec;
418 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
419
Mattc7d4b2f2005-06-27 14:59:41 +0200420 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200421 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
422}
423
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100424static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
425 struct snd_ctl_elem_info *uinfo)
426{
427 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
428 struct sigmatel_spec *spec = codec->spec;
429 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
430}
431
432static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
433 struct snd_ctl_elem_value *ucontrol)
434{
435 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
436 struct sigmatel_spec *spec = codec->spec;
437
438 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
439 return 0;
440}
441
442static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
443 struct snd_ctl_elem_value *ucontrol)
444{
445 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
446 struct sigmatel_spec *spec = codec->spec;
447
448 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
449 spec->mono_nid, &spec->cur_mmux);
450}
451
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200452#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
453
454static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
455 struct snd_ctl_elem_value *ucontrol)
456{
457 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100458 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200459 struct sigmatel_spec *spec = codec->spec;
460
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100461 ucontrol->value.integer.value[0] = !!(spec->aloopback &
462 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200463 return 0;
464}
465
466static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
468{
469 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
470 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100471 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200472 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100473 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200474
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100475 idx_val = spec->aloopback_mask << idx;
476 if (ucontrol->value.integer.value[0])
477 val = spec->aloopback | idx_val;
478 else
479 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100480 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200481 return 0;
482
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100483 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200484
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100485 /* Only return the bits defined by the shift value of the
486 * first two bytes of the mask
487 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200488 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100489 kcontrol->private_value & 0xFFFF, 0x0);
490 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200491
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100492 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200493 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100494 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200495 } else {
496 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100497 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200498 }
499
500 snd_hda_codec_write_cache(codec, codec->afg, 0,
501 kcontrol->private_value >> 16, dac_mode);
502
503 return 1;
504}
505
Mattc7d4b2f2005-06-27 14:59:41 +0200506static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200507 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200508 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200509 {}
510};
511
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200512static struct hda_verb stac9200_eapd_init[] = {
513 /* set dac0mux for dac converter */
514 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
515 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
516 {}
517};
518
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100519static struct hda_verb stac92hd73xx_6ch_core_init[] = {
520 /* set master volume and direct control */
521 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
522 /* setup audio connections */
523 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
524 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
525 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
526 /* setup adcs to point to mixer */
527 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
528 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100529 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
530 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
531 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
532 /* setup import muxs */
533 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
534 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
535 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
536 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
537 {}
538};
539
Matthew Ranostayd654a662008-03-14 08:46:51 +0100540static struct hda_verb dell_eq_core_init[] = {
541 /* set master volume to max value without distortion
542 * and direct control */
543 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
544 /* setup audio connections */
545 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
546 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
547 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
548 /* setup adcs to point to mixer */
549 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
550 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
551 /* setup import muxs */
552 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
553 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
554 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
555 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
556 {}
557};
558
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100559static struct hda_verb dell_m6_core_init[] = {
560 /* set master volume and direct control */
561 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
562 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100563 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
564 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100565 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
566 /* setup adcs to point to mixer */
567 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
568 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
569 /* setup import muxs */
570 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
571 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
572 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
573 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
574 {}
575};
576
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100577static struct hda_verb stac92hd73xx_8ch_core_init[] = {
578 /* set master volume and direct control */
579 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
580 /* setup audio connections */
581 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
582 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
583 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
584 /* connect hp ports to dac3 */
585 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
586 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
587 /* setup adcs to point to mixer */
588 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
589 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100590 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
591 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
592 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
593 /* setup import muxs */
594 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
595 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
596 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
597 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
598 {}
599};
600
601static struct hda_verb stac92hd73xx_10ch_core_init[] = {
602 /* set master volume and direct control */
603 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
604 /* setup audio connections */
605 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
606 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
607 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
608 /* dac3 is connected to import3 mux */
609 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
610 /* connect hp ports to dac4 */
611 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
612 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
613 /* setup adcs to point to mixer */
614 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
615 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100616 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
617 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
618 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
619 /* setup import muxs */
620 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
621 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
622 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
623 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
624 {}
625};
626
Matthew Ranostaye035b842007-11-06 11:53:55 +0100627static struct hda_verb stac92hd71bxx_core_init[] = {
628 /* set master volume and direct control */
629 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
630 /* connect headphone jack to dac1 */
631 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100632 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
633 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
634 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
635 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
636 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100637};
638
639static struct hda_verb stac92hd71bxx_analog_core_init[] = {
640 /* set master volume and direct control */
641 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
642 /* connect headphone jack to dac1 */
643 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100644 /* connect ports 0d and 0f to audio mixer */
645 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
646 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100647 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100648 /* unmute dac0 input in audio mixer */
649 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100650 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
651 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
652 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
653 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100654 {}
655};
656
Tobin Davis8e21c342007-01-08 11:04:17 +0100657static struct hda_verb stac925x_core_init[] = {
658 /* set dac0mux for dac converter */
659 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
660 {}
661};
662
Mattc7d4b2f2005-06-27 14:59:41 +0200663static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200664 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200665 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200666 {}
667};
668
Tobin Davis93ed1502006-09-01 21:03:12 +0200669static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200670 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200671 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200672 /* unmute node 0x1b */
673 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
674 /* select node 0x03 as DAC */
675 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
676 {}
677};
678
Matt Porter3cc08dc2006-01-23 15:27:49 +0100679static struct hda_verb stac927x_core_init[] = {
680 /* set master volume and direct control */
681 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
682 {}
683};
684
Matt Porterf3302a52006-07-31 12:49:34 +0200685static struct hda_verb stac9205_core_init[] = {
686 /* set master volume and direct control */
687 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
688 {}
689};
690
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100691#define STAC_MONO_MUX \
692 { \
693 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
694 .name = "Mono Mux", \
695 .count = 1, \
696 .info = stac92xx_mono_mux_enum_info, \
697 .get = stac92xx_mono_mux_enum_get, \
698 .put = stac92xx_mono_mux_enum_put, \
699 }
700
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200701#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200702 { \
703 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
704 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200705 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200706 .info = stac92xx_mux_enum_info, \
707 .get = stac92xx_mux_enum_get, \
708 .put = stac92xx_mux_enum_put, \
709 }
710
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100711#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200712 { \
713 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
714 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100715 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200716 .info = stac92xx_aloopback_info, \
717 .get = stac92xx_aloopback_get, \
718 .put = stac92xx_aloopback_put, \
719 .private_value = verb_read | (verb_write << 16), \
720 }
721
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100722static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200723 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
724 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200725 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200726 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
727 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200728 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200729 { } /* end */
730};
731
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100733 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
734
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100735 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
736 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
737
738 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
739 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
740
741 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
742 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
743
744 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
745 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
746
747 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
748 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
749
750 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
751 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
752
753 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
754 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
755 { } /* end */
756};
757
758static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100759 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
760
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100761 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
762 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
763
764 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
765 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
766
767 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
768 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
769
770 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
771 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
772
773 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
774 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
775
776 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
777 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
778
779 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
780 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
781 { } /* end */
782};
783
784static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100785 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
786
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100787 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
788 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
789
790 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
791 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
792
793 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
794 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
795
796 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
797 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
798
799 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
800 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
801
802 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
803 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
804
805 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
806 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
807 { } /* end */
808};
809
Matthew Ranostay541eee82007-12-14 12:08:04 +0100810static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100811 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100812
Matthew Ranostay9b359472007-11-07 13:03:12 +0100813 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
814 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
815 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
816
817 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
818 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
819 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
820
821 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
822 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100823 { } /* end */
824};
825
Matthew Ranostay541eee82007-12-14 12:08:04 +0100826static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100827 STAC_INPUT_SOURCE(2),
828 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
829
Matthew Ranostay541eee82007-12-14 12:08:04 +0100830 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
831 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
832 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
833
834 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
835 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
836 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
837 { } /* end */
838};
839
Tobin Davis8e21c342007-01-08 11:04:17 +0100840static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200841 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100842 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +0200843 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +0100844 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
845 { } /* end */
846};
847
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100848static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200849 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100850 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200851
852 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
853 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
854 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
855
856 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
857 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
858 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
859
860 { } /* end */
861};
862
863/* This needs to be generated dynamically based on sequence */
864static struct snd_kcontrol_new stac922x_mixer[] = {
865 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200866 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
867 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
868 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
869
870 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
871 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
872 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
873 { } /* end */
874};
875
876
877static struct snd_kcontrol_new stac927x_mixer[] = {
878 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100879 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200880
881 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
882 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
883 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
884
885 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
886 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
887 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
888
889 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
890 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
891 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200892 { } /* end */
893};
894
Takashi Iwai1697055e2007-12-18 18:05:52 +0100895static struct snd_kcontrol_new stac_dmux_mixer = {
896 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
897 .name = "Digital Input Source",
898 /* count set later */
899 .info = stac92xx_dmux_enum_info,
900 .get = stac92xx_dmux_enum_get,
901 .put = stac92xx_dmux_enum_put,
902};
903
Takashi Iwai2134ea42008-01-10 16:53:55 +0100904static const char *slave_vols[] = {
905 "Front Playback Volume",
906 "Surround Playback Volume",
907 "Center Playback Volume",
908 "LFE Playback Volume",
909 "Side Playback Volume",
910 "Headphone Playback Volume",
911 "Headphone Playback Volume",
912 "Speaker Playback Volume",
913 "External Speaker Playback Volume",
914 "Speaker2 Playback Volume",
915 NULL
916};
917
918static const char *slave_sws[] = {
919 "Front Playback Switch",
920 "Surround Playback Switch",
921 "Center Playback Switch",
922 "LFE Playback Switch",
923 "Side Playback Switch",
924 "Headphone Playback Switch",
925 "Headphone Playback Switch",
926 "Speaker Playback Switch",
927 "External Speaker Playback Switch",
928 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100929 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100930 NULL
931};
932
Matt2f2f4252005-04-13 14:45:30 +0200933static int stac92xx_build_controls(struct hda_codec *codec)
934{
935 struct sigmatel_spec *spec = codec->spec;
936 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200937 int i;
Matt2f2f4252005-04-13 14:45:30 +0200938
939 err = snd_hda_add_new_ctls(codec, spec->mixer);
940 if (err < 0)
941 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200942
943 for (i = 0; i < spec->num_mixers; i++) {
944 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
945 if (err < 0)
946 return err;
947 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100948 if (spec->num_dmuxes > 0) {
949 stac_dmux_mixer.count = spec->num_dmuxes;
950 err = snd_ctl_add(codec->bus->card,
951 snd_ctl_new1(&stac_dmux_mixer, codec));
952 if (err < 0)
953 return err;
954 }
Mattc7d4b2f2005-06-27 14:59:41 +0200955
Mattdabbed62005-06-14 10:19:34 +0200956 if (spec->multiout.dig_out_nid) {
957 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
958 if (err < 0)
959 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100960 err = snd_hda_create_spdif_share_sw(codec,
961 &spec->multiout);
962 if (err < 0)
963 return err;
964 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200965 }
966 if (spec->dig_in_nid) {
967 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
968 if (err < 0)
969 return err;
970 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100971
972 /* if we have no master control, let's create it */
973 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100974 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100975 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100976 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100977 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100978 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100979 if (err < 0)
980 return err;
981 }
982 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
983 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
984 NULL, slave_sws);
985 if (err < 0)
986 return err;
987 }
988
Mattdabbed62005-06-14 10:19:34 +0200989 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200990}
991
Matt Porter403d1942005-11-29 15:00:51 +0100992static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200993 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200994 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
995};
996
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200997/*
998 STAC 9200 pin configs for
999 102801A8
1000 102801DE
1001 102801E8
1002*/
1003static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001004 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1005 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001006};
1007
1008/*
1009 STAC 9200 pin configs for
1010 102801C0
1011 102801C1
1012*/
1013static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001014 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1015 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001016};
1017
1018/*
1019 STAC 9200 pin configs for
1020 102801C4 (Dell Dimension E310)
1021 102801C5
1022 102801C7
1023 102801D9
1024 102801DA
1025 102801E3
1026*/
1027static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001028 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1029 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001030};
1031
1032
1033/*
1034 STAC 9200-32 pin configs for
1035 102801B5 (Dell Inspiron 630m)
1036 102801D8 (Dell Inspiron 640m)
1037*/
1038static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001039 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1040 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001041};
1042
1043/*
1044 STAC 9200-32 pin configs for
1045 102801C2 (Dell Latitude D620)
1046 102801C8
1047 102801CC (Dell Latitude D820)
1048 102801D4
1049 102801D6
1050*/
1051static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001052 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1053 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001054};
1055
1056/*
1057 STAC 9200-32 pin configs for
1058 102801CE (Dell XPS M1710)
1059 102801CF (Dell Precision M90)
1060*/
1061static unsigned int dell9200_m23_pin_configs[8] = {
1062 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1063 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1064};
1065
1066/*
1067 STAC 9200-32 pin configs for
1068 102801C9
1069 102801CA
1070 102801CB (Dell Latitude 120L)
1071 102801D3
1072*/
1073static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001074 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1075 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001076};
1077
1078/*
1079 STAC 9200-32 pin configs for
1080 102801BD (Dell Inspiron E1505n)
1081 102801EE
1082 102801EF
1083*/
1084static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001085 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1086 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001087};
1088
1089/*
1090 STAC 9200-32 pin configs for
1091 102801F5 (Dell Inspiron 1501)
1092 102801F6
1093*/
1094static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001095 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1096 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001097};
1098
1099/*
1100 STAC 9200-32
1101 102801CD (Dell Inspiron E1705/9400)
1102*/
1103static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001104 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1105 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001106};
1107
Tobin Davisbf277782008-02-03 20:31:47 +01001108static unsigned int oqo9200_pin_configs[8] = {
1109 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1110 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1111};
1112
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001113
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001114static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1115 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001116 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001117 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1118 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1119 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1120 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1121 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1122 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1123 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1124 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1125 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1126 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001127 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001128};
1129
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001130static const char *stac9200_models[STAC_9200_MODELS] = {
1131 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001132 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001133 [STAC_9200_DELL_D21] = "dell-d21",
1134 [STAC_9200_DELL_D22] = "dell-d22",
1135 [STAC_9200_DELL_D23] = "dell-d23",
1136 [STAC_9200_DELL_M21] = "dell-m21",
1137 [STAC_9200_DELL_M22] = "dell-m22",
1138 [STAC_9200_DELL_M23] = "dell-m23",
1139 [STAC_9200_DELL_M24] = "dell-m24",
1140 [STAC_9200_DELL_M25] = "dell-m25",
1141 [STAC_9200_DELL_M26] = "dell-m26",
1142 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001143 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001144 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001145};
1146
1147static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1148 /* SigmaTel reference board */
1149 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1150 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001151 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1153 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001154 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001155 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1156 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1157 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1158 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1159 "unknown Dell", STAC_9200_DELL_D22),
1160 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1161 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001162 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001163 "Dell Latitude D620", STAC_9200_DELL_M22),
1164 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1165 "unknown Dell", STAC_9200_DELL_D23),
1166 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1167 "unknown Dell", STAC_9200_DELL_D23),
1168 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1169 "unknown Dell", STAC_9200_DELL_M22),
1170 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1171 "unknown Dell", STAC_9200_DELL_M24),
1172 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1173 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001174 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001175 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001176 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001177 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001178 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001179 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001180 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001181 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001182 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001183 "Dell Precision M90", STAC_9200_DELL_M23),
1184 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1185 "unknown Dell", STAC_9200_DELL_M22),
1186 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1187 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001188 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001189 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001190 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001191 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1192 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1193 "unknown Dell", STAC_9200_DELL_D23),
1194 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1195 "unknown Dell", STAC_9200_DELL_D23),
1196 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1197 "unknown Dell", STAC_9200_DELL_D21),
1198 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1199 "unknown Dell", STAC_9200_DELL_D23),
1200 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1201 "unknown Dell", STAC_9200_DELL_D21),
1202 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1203 "unknown Dell", STAC_9200_DELL_M25),
1204 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1205 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001206 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001207 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1208 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1209 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001210 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001211 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001212 /* Gateway machines needs EAPD to be set on resume */
1213 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1214 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1215 STAC_9200_GATEWAY),
1216 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1217 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001218 /* OQO Mobile */
1219 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001220 {} /* terminator */
1221};
1222
Tobin Davis8e21c342007-01-08 11:04:17 +01001223static unsigned int ref925x_pin_configs[8] = {
1224 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001225 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001226};
1227
1228static unsigned int stac925x_MA6_pin_configs[8] = {
1229 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1230 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1231};
1232
Tobin Davis2c11f952007-05-17 09:36:34 +02001233static unsigned int stac925x_PA6_pin_configs[8] = {
1234 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1235 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1236};
1237
Tobin Davis8e21c342007-01-08 11:04:17 +01001238static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001239 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1240 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001241};
1242
1243static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1244 [STAC_REF] = ref925x_pin_configs,
1245 [STAC_M2_2] = stac925xM2_2_pin_configs,
1246 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001247 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001248};
1249
1250static const char *stac925x_models[STAC_925x_MODELS] = {
1251 [STAC_REF] = "ref",
1252 [STAC_M2_2] = "m2-2",
1253 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001254 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001255};
1256
1257static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1258 /* SigmaTel reference board */
1259 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001260 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001261 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1262 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1263 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001264 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001265 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1266 {} /* terminator */
1267};
1268
Matthew Ranostaya7662642008-02-21 07:51:14 +01001269static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001270 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1271 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1272 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001273 0x01452050,
1274};
1275
1276static unsigned int dell_m6_pin_configs[13] = {
1277 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001278 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001279 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1280 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001281};
1282
1283static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001284 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1285 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001286};
1287
1288static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1289 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001290 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001291};
1292
1293static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1294 /* SigmaTel reference board */
1295 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001296 "DFI LanParty", STAC_92HD73XX_REF),
1297 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1298 "unknown Dell", STAC_DELL_M6),
1299 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1300 "unknown Dell", STAC_DELL_M6),
1301 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1302 "unknown Dell", STAC_DELL_M6),
1303 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1304 "unknown Dell", STAC_DELL_M6),
1305 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1306 "unknown Dell", STAC_DELL_M6),
1307 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1308 "unknown Dell", STAC_DELL_M6),
1309 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1310 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001311 {} /* terminator */
1312};
1313
Matthew Ranostaye035b842007-11-06 11:53:55 +01001314static unsigned int ref92hd71bxx_pin_configs[10] = {
1315 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001316 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001317 0x90a000f0, 0x01452050,
1318};
1319
Matthew Ranostaya7662642008-02-21 07:51:14 +01001320static unsigned int dell_m4_1_pin_configs[13] = {
1321 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001322 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001323 0x40f000f0, 0x4f0000f0,
1324};
1325
1326static unsigned int dell_m4_2_pin_configs[13] = {
1327 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1328 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1329 0x40f000f0, 0x044413b0,
1330};
1331
Matthew Ranostaye035b842007-11-06 11:53:55 +01001332static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1333 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001334 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1335 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001336};
1337
1338static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1339 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001340 [STAC_DELL_M4_1] = "dell-m4-1",
1341 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001342};
1343
1344static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1345 /* SigmaTel reference board */
1346 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1347 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001348 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1349 "unknown Dell", STAC_DELL_M4_1),
1350 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1351 "unknown Dell", STAC_DELL_M4_1),
1352 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1353 "unknown Dell", STAC_DELL_M4_1),
1354 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1355 "unknown Dell", STAC_DELL_M4_1),
1356 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1357 "unknown Dell", STAC_DELL_M4_1),
1358 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1359 "unknown Dell", STAC_DELL_M4_1),
1360 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1361 "unknown Dell", STAC_DELL_M4_1),
1362 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1363 "unknown Dell", STAC_DELL_M4_2),
1364 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1365 "unknown Dell", STAC_DELL_M4_2),
1366 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1367 "unknown Dell", STAC_DELL_M4_2),
1368 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1369 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001370 {} /* terminator */
1371};
1372
Matt Porter403d1942005-11-29 15:00:51 +01001373static unsigned int ref922x_pin_configs[10] = {
1374 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1375 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001376 0x40000100, 0x40000100,
1377};
1378
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001379/*
1380 STAC 922X pin configs for
1381 102801A7
1382 102801AB
1383 102801A9
1384 102801D1
1385 102801D2
1386*/
1387static unsigned int dell_922x_d81_pin_configs[10] = {
1388 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1389 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1390 0x01813122, 0x400001f2,
1391};
1392
1393/*
1394 STAC 922X pin configs for
1395 102801AC
1396 102801D0
1397*/
1398static unsigned int dell_922x_d82_pin_configs[10] = {
1399 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1400 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1401 0x01813122, 0x400001f1,
1402};
1403
1404/*
1405 STAC 922X pin configs for
1406 102801BF
1407*/
1408static unsigned int dell_922x_m81_pin_configs[10] = {
1409 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1410 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1411 0x40C003f1, 0x405003f0,
1412};
1413
1414/*
1415 STAC 9221 A1 pin configs for
1416 102801D7 (Dell XPS M1210)
1417*/
1418static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001419 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1420 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001421 0x508003f3, 0x405003f4,
1422};
1423
Matt Porter403d1942005-11-29 15:00:51 +01001424static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001425 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001426 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1427 0x02a19120, 0x40000100,
1428};
1429
1430static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001431 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1432 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001433 0x02a19320, 0x40000100,
1434};
1435
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001436static unsigned int intel_mac_v1_pin_configs[10] = {
1437 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1438 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001439 0x400000fc, 0x400000fb,
1440};
1441
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001442static unsigned int intel_mac_v2_pin_configs[10] = {
1443 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1444 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001445 0x400000fc, 0x400000fb,
1446};
1447
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001448static unsigned int intel_mac_v3_pin_configs[10] = {
1449 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1450 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1451 0x400000fc, 0x400000fb,
1452};
1453
1454static unsigned int intel_mac_v4_pin_configs[10] = {
1455 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1456 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1457 0x400000fc, 0x400000fb,
1458};
1459
1460static unsigned int intel_mac_v5_pin_configs[10] = {
1461 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1462 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1463 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001464};
1465
Takashi Iwai76c08822007-06-19 12:17:42 +02001466
Takashi Iwai19039bd2006-06-28 15:52:16 +02001467static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001468 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001469 [STAC_D945GTP3] = d945gtp3_pin_configs,
1470 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001471 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1472 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1473 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1474 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1475 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001476 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001477 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1478 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1479 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1480 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1481 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1482 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001483 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1484 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1485 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1486 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001487};
1488
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001489static const char *stac922x_models[STAC_922X_MODELS] = {
1490 [STAC_D945_REF] = "ref",
1491 [STAC_D945GTP5] = "5stack",
1492 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001493 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1494 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1495 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1496 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1497 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001498 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001499 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001500 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001501 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1502 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001503 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001504 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001505 [STAC_922X_DELL_D81] = "dell-d81",
1506 [STAC_922X_DELL_D82] = "dell-d82",
1507 [STAC_922X_DELL_M81] = "dell-m81",
1508 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001509};
1510
1511static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1512 /* SigmaTel reference board */
1513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1514 "DFI LanParty", STAC_D945_REF),
1515 /* Intel 945G based systems */
1516 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1517 "Intel D945G", STAC_D945GTP3),
1518 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1519 "Intel D945G", STAC_D945GTP3),
1520 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1521 "Intel D945G", STAC_D945GTP3),
1522 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1523 "Intel D945G", STAC_D945GTP3),
1524 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1525 "Intel D945G", STAC_D945GTP3),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1527 "Intel D945G", STAC_D945GTP3),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1529 "Intel D945G", STAC_D945GTP3),
1530 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1531 "Intel D945G", STAC_D945GTP3),
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1533 "Intel D945G", STAC_D945GTP3),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1535 "Intel D945G", STAC_D945GTP3),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1537 "Intel D945G", STAC_D945GTP3),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1539 "Intel D945G", STAC_D945GTP3),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1541 "Intel D945G", STAC_D945GTP3),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1543 "Intel D945G", STAC_D945GTP3),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1545 "Intel D945G", STAC_D945GTP3),
1546 /* Intel D945G 5-stack systems */
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1548 "Intel D945G", STAC_D945GTP5),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1550 "Intel D945G", STAC_D945GTP5),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1552 "Intel D945G", STAC_D945GTP5),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1554 "Intel D945G", STAC_D945GTP5),
1555 /* Intel 945P based systems */
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1557 "Intel D945P", STAC_D945GTP3),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1559 "Intel D945P", STAC_D945GTP3),
1560 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1561 "Intel D945P", STAC_D945GTP3),
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1563 "Intel D945P", STAC_D945GTP3),
1564 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1565 "Intel D945P", STAC_D945GTP3),
1566 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1567 "Intel D945P", STAC_D945GTP5),
1568 /* other systems */
1569 /* Apple Mac Mini (early 2006) */
1570 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001571 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001572 /* Dell systems */
1573 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1574 "unknown Dell", STAC_922X_DELL_D81),
1575 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1576 "unknown Dell", STAC_922X_DELL_D81),
1577 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1578 "unknown Dell", STAC_922X_DELL_D81),
1579 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1580 "unknown Dell", STAC_922X_DELL_D82),
1581 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1582 "unknown Dell", STAC_922X_DELL_M81),
1583 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1584 "unknown Dell", STAC_922X_DELL_D82),
1585 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1586 "unknown Dell", STAC_922X_DELL_D81),
1587 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1588 "unknown Dell", STAC_922X_DELL_D81),
1589 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1590 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001591 {} /* terminator */
1592};
1593
Matt Porter3cc08dc2006-01-23 15:27:49 +01001594static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001595 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1596 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1597 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1598 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001599};
1600
Tobin Davis93ed1502006-09-01 21:03:12 +02001601static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001602 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1603 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1604 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1605 0x40000100, 0x40000100
1606};
1607
Tobin Davis93ed1502006-09-01 21:03:12 +02001608static unsigned int d965_5st_pin_configs[14] = {
1609 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1610 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1611 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1612 0x40000100, 0x40000100
1613};
1614
Tobin Davis4ff076e2007-08-07 11:48:12 +02001615static unsigned int dell_3st_pin_configs[14] = {
1616 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1617 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001618 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001619 0x40c003fc, 0x40000100
1620};
1621
Tobin Davis93ed1502006-09-01 21:03:12 +02001622static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001623 [STAC_D965_REF] = ref927x_pin_configs,
1624 [STAC_D965_3ST] = d965_3st_pin_configs,
1625 [STAC_D965_5ST] = d965_5st_pin_configs,
1626 [STAC_DELL_3ST] = dell_3st_pin_configs,
1627 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001628};
1629
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001630static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001631 [STAC_D965_REF] = "ref",
1632 [STAC_D965_3ST] = "3stack",
1633 [STAC_D965_5ST] = "5stack",
1634 [STAC_DELL_3ST] = "dell-3stack",
1635 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001636};
1637
1638static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1639 /* SigmaTel reference board */
1640 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1641 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001642 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001643 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1644 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001645 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001646 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1648 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1649 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1650 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1652 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1653 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1654 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1656 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1657 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1658 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1659 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1660 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1661 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001662 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001663 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001664 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001665 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1666 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001667 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001668 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1669 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001670 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1671 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1672 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1674 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1675 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001676 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001677 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1678 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1679 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1680 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1681 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1682 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1683 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1684 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1685 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001686 {} /* terminator */
1687};
1688
Matt Porterf3302a52006-07-31 12:49:34 +02001689static unsigned int ref9205_pin_configs[12] = {
1690 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001691 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001692 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001693};
1694
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001695/*
1696 STAC 9205 pin configs for
1697 102801F1
1698 102801F2
1699 102801FC
1700 102801FD
1701 10280204
1702 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001703 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001704*/
1705static unsigned int dell_9205_m42_pin_configs[12] = {
1706 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1707 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1708 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1709};
1710
1711/*
1712 STAC 9205 pin configs for
1713 102801F9
1714 102801FA
1715 102801FE
1716 102801FF (Dell Precision M4300)
1717 10280206
1718 10280200
1719 10280201
1720*/
1721static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001722 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1723 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1724 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1725};
1726
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001727static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001728 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1729 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1730 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1731};
1732
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001733static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001734 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001735 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1736 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1737 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001738};
1739
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001740static const char *stac9205_models[STAC_9205_MODELS] = {
1741 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001742 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001743 [STAC_9205_DELL_M43] = "dell-m43",
1744 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001745};
1746
1747static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1748 /* SigmaTel reference board */
1749 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1750 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001751 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1752 "unknown Dell", STAC_9205_DELL_M42),
1753 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1754 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001755 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001756 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001757 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1758 "Dell Precision", STAC_9205_DELL_M43),
1759 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1760 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001761 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1762 "unknown Dell", STAC_9205_DELL_M42),
1763 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1764 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001765 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1766 "Dell Precision", STAC_9205_DELL_M43),
1767 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001768 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001769 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1770 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02001771 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1772 "Dell Precision", STAC_9205_DELL_M43),
1773 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1774 "Dell Precision", STAC_9205_DELL_M43),
1775 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1776 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001777 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1778 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001779 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1780 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001781 {} /* terminator */
1782};
1783
Richard Fish11b44bb2006-08-23 18:31:34 +02001784static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1785{
1786 int i;
1787 struct sigmatel_spec *spec = codec->spec;
1788
1789 if (! spec->bios_pin_configs) {
1790 spec->bios_pin_configs = kcalloc(spec->num_pins,
1791 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1792 if (! spec->bios_pin_configs)
1793 return -ENOMEM;
1794 }
1795
1796 for (i = 0; i < spec->num_pins; i++) {
1797 hda_nid_t nid = spec->pin_nids[i];
1798 unsigned int pin_cfg;
1799
1800 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1801 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1802 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1803 nid, pin_cfg);
1804 spec->bios_pin_configs[i] = pin_cfg;
1805 }
1806
1807 return 0;
1808}
1809
Matthew Ranostay87d48362007-07-17 11:52:24 +02001810static void stac92xx_set_config_reg(struct hda_codec *codec,
1811 hda_nid_t pin_nid, unsigned int pin_config)
1812{
1813 int i;
1814 snd_hda_codec_write(codec, pin_nid, 0,
1815 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1816 pin_config & 0x000000ff);
1817 snd_hda_codec_write(codec, pin_nid, 0,
1818 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1819 (pin_config & 0x0000ff00) >> 8);
1820 snd_hda_codec_write(codec, pin_nid, 0,
1821 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1822 (pin_config & 0x00ff0000) >> 16);
1823 snd_hda_codec_write(codec, pin_nid, 0,
1824 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1825 pin_config >> 24);
1826 i = snd_hda_codec_read(codec, pin_nid, 0,
1827 AC_VERB_GET_CONFIG_DEFAULT,
1828 0x00);
1829 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1830 pin_nid, i);
1831}
1832
Matt2f2f4252005-04-13 14:45:30 +02001833static void stac92xx_set_config_regs(struct hda_codec *codec)
1834{
1835 int i;
1836 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001837
Matthew Ranostay87d48362007-07-17 11:52:24 +02001838 if (!spec->pin_configs)
1839 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001840
Matthew Ranostay87d48362007-07-17 11:52:24 +02001841 for (i = 0; i < spec->num_pins; i++)
1842 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1843 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001844}
Matt2f2f4252005-04-13 14:45:30 +02001845
Matt2f2f4252005-04-13 14:45:30 +02001846/*
1847 * Analog playback callbacks
1848 */
1849static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1850 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001851 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001852{
1853 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001854 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1855 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001856}
1857
1858static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1859 struct hda_codec *codec,
1860 unsigned int stream_tag,
1861 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001862 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001863{
1864 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001865 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001866}
1867
1868static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1869 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001870 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001871{
1872 struct sigmatel_spec *spec = codec->spec;
1873 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1874}
1875
1876/*
Mattdabbed62005-06-14 10:19:34 +02001877 * Digital playback callbacks
1878 */
1879static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1880 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001881 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001882{
1883 struct sigmatel_spec *spec = codec->spec;
1884 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1885}
1886
1887static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1888 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001889 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001890{
1891 struct sigmatel_spec *spec = codec->spec;
1892 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1893}
1894
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001895static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1896 struct hda_codec *codec,
1897 unsigned int stream_tag,
1898 unsigned int format,
1899 struct snd_pcm_substream *substream)
1900{
1901 struct sigmatel_spec *spec = codec->spec;
1902 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1903 stream_tag, format, substream);
1904}
1905
Mattdabbed62005-06-14 10:19:34 +02001906
1907/*
Matt2f2f4252005-04-13 14:45:30 +02001908 * Analog capture callbacks
1909 */
1910static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1911 struct hda_codec *codec,
1912 unsigned int stream_tag,
1913 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001914 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001915{
1916 struct sigmatel_spec *spec = codec->spec;
1917
1918 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1919 stream_tag, 0, format);
1920 return 0;
1921}
1922
1923static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1924 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001925 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001926{
1927 struct sigmatel_spec *spec = codec->spec;
1928
Takashi Iwai888afa12008-03-18 09:57:50 +01001929 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Matt2f2f4252005-04-13 14:45:30 +02001930 return 0;
1931}
1932
Mattdabbed62005-06-14 10:19:34 +02001933static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1934 .substreams = 1,
1935 .channels_min = 2,
1936 .channels_max = 2,
1937 /* NID is set in stac92xx_build_pcms */
1938 .ops = {
1939 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001940 .close = stac92xx_dig_playback_pcm_close,
1941 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001942 },
1943};
1944
1945static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1946 .substreams = 1,
1947 .channels_min = 2,
1948 .channels_max = 2,
1949 /* NID is set in stac92xx_build_pcms */
1950};
1951
Matt2f2f4252005-04-13 14:45:30 +02001952static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1953 .substreams = 1,
1954 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001955 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001956 .nid = 0x02, /* NID to query formats and rates */
1957 .ops = {
1958 .open = stac92xx_playback_pcm_open,
1959 .prepare = stac92xx_playback_pcm_prepare,
1960 .cleanup = stac92xx_playback_pcm_cleanup
1961 },
1962};
1963
Matt Porter3cc08dc2006-01-23 15:27:49 +01001964static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1965 .substreams = 1,
1966 .channels_min = 2,
1967 .channels_max = 2,
1968 .nid = 0x06, /* NID to query formats and rates */
1969 .ops = {
1970 .open = stac92xx_playback_pcm_open,
1971 .prepare = stac92xx_playback_pcm_prepare,
1972 .cleanup = stac92xx_playback_pcm_cleanup
1973 },
1974};
1975
Matt2f2f4252005-04-13 14:45:30 +02001976static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001977 .channels_min = 2,
1978 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001979 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001980 .ops = {
1981 .prepare = stac92xx_capture_pcm_prepare,
1982 .cleanup = stac92xx_capture_pcm_cleanup
1983 },
1984};
1985
1986static int stac92xx_build_pcms(struct hda_codec *codec)
1987{
1988 struct sigmatel_spec *spec = codec->spec;
1989 struct hda_pcm *info = spec->pcm_rec;
1990
1991 codec->num_pcms = 1;
1992 codec->pcm_info = info;
1993
Mattc7d4b2f2005-06-27 14:59:41 +02001994 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001995 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001996 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001997 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001998 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001999
2000 if (spec->alt_switch) {
2001 codec->num_pcms++;
2002 info++;
2003 info->name = "STAC92xx Analog Alt";
2004 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2005 }
Matt2f2f4252005-04-13 14:45:30 +02002006
Mattdabbed62005-06-14 10:19:34 +02002007 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2008 codec->num_pcms++;
2009 info++;
2010 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002011 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002012 if (spec->multiout.dig_out_nid) {
2013 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2014 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2015 }
2016 if (spec->dig_in_nid) {
2017 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2018 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2019 }
2020 }
2021
Matt2f2f4252005-04-13 14:45:30 +02002022 return 0;
2023}
2024
Takashi Iwaic960a032006-03-23 17:06:28 +01002025static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2026{
2027 unsigned int pincap = snd_hda_param_read(codec, nid,
2028 AC_PAR_PIN_CAP);
2029 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2030 if (pincap & AC_PINCAP_VREF_100)
2031 return AC_PINCTL_VREF_100;
2032 if (pincap & AC_PINCAP_VREF_80)
2033 return AC_PINCTL_VREF_80;
2034 if (pincap & AC_PINCAP_VREF_50)
2035 return AC_PINCTL_VREF_50;
2036 if (pincap & AC_PINCAP_VREF_GRD)
2037 return AC_PINCTL_VREF_GRD;
2038 return 0;
2039}
2040
Matt Porter403d1942005-11-29 15:00:51 +01002041static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2042
2043{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002044 snd_hda_codec_write_cache(codec, nid, 0,
2045 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002046}
2047
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002048#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2049
2050static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2051 struct snd_ctl_elem_value *ucontrol)
2052{
2053 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2054 struct sigmatel_spec *spec = codec->spec;
2055
2056 ucontrol->value.integer.value[0] = spec->hp_switch;
2057 return 0;
2058}
2059
2060static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2061 struct snd_ctl_elem_value *ucontrol)
2062{
2063 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2064 struct sigmatel_spec *spec = codec->spec;
2065
2066 spec->hp_switch = ucontrol->value.integer.value[0];
2067
2068 /* check to be sure that the ports are upto date with
2069 * switch changes
2070 */
2071 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2072
2073 return 1;
2074}
2075
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002076#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002077
2078static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2079{
2080 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2081 struct sigmatel_spec *spec = codec->spec;
2082 int io_idx = kcontrol-> private_value & 0xff;
2083
2084 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2085 return 0;
2086}
2087
2088static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2089{
2090 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2091 struct sigmatel_spec *spec = codec->spec;
2092 hda_nid_t nid = kcontrol->private_value >> 8;
2093 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002094 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002095
2096 spec->io_switch[io_idx] = val;
2097
2098 if (val)
2099 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002100 else {
2101 unsigned int pinctl = AC_PINCTL_IN_EN;
2102 if (io_idx) /* set VREF for mic */
2103 pinctl |= stac92xx_get_vref(codec, nid);
2104 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2105 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002106
2107 /* check the auto-mute again: we need to mute/unmute the speaker
2108 * appropriately according to the pin direction
2109 */
2110 if (spec->hp_detect)
2111 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2112
Matt Porter403d1942005-11-29 15:00:51 +01002113 return 1;
2114}
2115
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002116#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2117
2118static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2119 struct snd_ctl_elem_value *ucontrol)
2120{
2121 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2122 struct sigmatel_spec *spec = codec->spec;
2123
2124 ucontrol->value.integer.value[0] = spec->clfe_swap;
2125 return 0;
2126}
2127
2128static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2129 struct snd_ctl_elem_value *ucontrol)
2130{
2131 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2132 struct sigmatel_spec *spec = codec->spec;
2133 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002134 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002135
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002136 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002137 return 0;
2138
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002139 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002140
2141 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2142 spec->clfe_swap ? 0x4 : 0x0);
2143
2144 return 1;
2145}
2146
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002147#define STAC_CODEC_HP_SWITCH(xname) \
2148 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2149 .name = xname, \
2150 .index = 0, \
2151 .info = stac92xx_hp_switch_info, \
2152 .get = stac92xx_hp_switch_get, \
2153 .put = stac92xx_hp_switch_put, \
2154 }
2155
Matt Porter403d1942005-11-29 15:00:51 +01002156#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2157 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2158 .name = xname, \
2159 .index = 0, \
2160 .info = stac92xx_io_switch_info, \
2161 .get = stac92xx_io_switch_get, \
2162 .put = stac92xx_io_switch_put, \
2163 .private_value = xpval, \
2164 }
2165
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002166#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2167 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2168 .name = xname, \
2169 .index = 0, \
2170 .info = stac92xx_clfe_switch_info, \
2171 .get = stac92xx_clfe_switch_get, \
2172 .put = stac92xx_clfe_switch_put, \
2173 .private_value = xpval, \
2174 }
Matt Porter403d1942005-11-29 15:00:51 +01002175
Mattc7d4b2f2005-06-27 14:59:41 +02002176enum {
2177 STAC_CTL_WIDGET_VOL,
2178 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002179 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002180 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002181 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002182 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002183};
2184
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002185static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002186 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2187 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002188 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002189 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002190 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002191 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002192};
2193
2194/* add dynamic controls */
2195static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2196{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002197 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002198
2199 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2200 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2201
2202 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2203 if (! knew)
2204 return -ENOMEM;
2205 if (spec->kctl_alloc) {
2206 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2207 kfree(spec->kctl_alloc);
2208 }
2209 spec->kctl_alloc = knew;
2210 spec->num_kctl_alloc = num;
2211 }
2212
2213 knew = &spec->kctl_alloc[spec->num_kctl_used];
2214 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002215 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002216 if (! knew->name)
2217 return -ENOMEM;
2218 knew->private_value = val;
2219 spec->num_kctl_used++;
2220 return 0;
2221}
2222
Matt Porter403d1942005-11-29 15:00:51 +01002223/* flag inputs as additional dynamic lineouts */
2224static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2225{
2226 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002227 unsigned int wcaps, wtype;
2228 int i, num_dacs = 0;
2229
2230 /* use the wcaps cache to count all DACs available for line-outs */
2231 for (i = 0; i < codec->num_nodes; i++) {
2232 wcaps = codec->wcaps[i];
2233 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002234
Steve Longerbeam7b043892007-05-03 20:50:03 +02002235 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2236 num_dacs++;
2237 }
Matt Porter403d1942005-11-29 15:00:51 +01002238
Steve Longerbeam7b043892007-05-03 20:50:03 +02002239 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2240
Matt Porter403d1942005-11-29 15:00:51 +01002241 switch (cfg->line_outs) {
2242 case 3:
2243 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002244 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002245 cfg->line_out_pins[cfg->line_outs] =
2246 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002247 spec->line_switch = 1;
2248 cfg->line_outs++;
2249 }
2250 break;
2251 case 2:
2252 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002253 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002254 cfg->line_out_pins[cfg->line_outs] =
2255 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002256 spec->line_switch = 1;
2257 cfg->line_outs++;
2258 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002259 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002260 cfg->line_out_pins[cfg->line_outs] =
2261 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002262 spec->mic_switch = 1;
2263 cfg->line_outs++;
2264 }
2265 break;
2266 case 1:
2267 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002268 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002269 cfg->line_out_pins[cfg->line_outs] =
2270 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002271 spec->line_switch = 1;
2272 cfg->line_outs++;
2273 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002274 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002275 cfg->line_out_pins[cfg->line_outs] =
2276 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002277 spec->mic_switch = 1;
2278 cfg->line_outs++;
2279 }
2280 break;
2281 }
2282
2283 return 0;
2284}
2285
Steve Longerbeam7b043892007-05-03 20:50:03 +02002286
2287static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2288{
2289 int i;
2290
2291 for (i = 0; i < spec->multiout.num_dacs; i++) {
2292 if (spec->multiout.dac_nids[i] == nid)
2293 return 1;
2294 }
2295
2296 return 0;
2297}
2298
Matt Porter3cc08dc2006-01-23 15:27:49 +01002299/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002300 * Fill in the dac_nids table from the parsed pin configuration
2301 * This function only works when every pin in line_out_pins[]
2302 * contains atleast one DAC in its connection list. Some 92xx
2303 * codecs are not connected directly to a DAC, such as the 9200
2304 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002305 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002306static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002307 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002308{
2309 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002310 int i, j, conn_len = 0;
2311 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2312 unsigned int wcaps, wtype;
2313
Mattc7d4b2f2005-06-27 14:59:41 +02002314 for (i = 0; i < cfg->line_outs; i++) {
2315 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002316 conn_len = snd_hda_get_connections(codec, nid, conn,
2317 HDA_MAX_CONNECTIONS);
2318 for (j = 0; j < conn_len; j++) {
2319 wcaps = snd_hda_param_read(codec, conn[j],
2320 AC_PAR_AUDIO_WIDGET_CAP);
2321 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002322 if (wtype != AC_WID_AUD_OUT ||
2323 (wcaps & AC_WCAP_DIGITAL))
2324 continue;
2325 /* conn[j] is a DAC routed to this line-out */
2326 if (!is_in_dac_nids(spec, conn[j]))
2327 break;
2328 }
2329
2330 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002331 if (spec->multiout.num_dacs > 0) {
2332 /* we have already working output pins,
2333 * so let's drop the broken ones again
2334 */
2335 cfg->line_outs = spec->multiout.num_dacs;
2336 break;
2337 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002338 /* error out, no available DAC found */
2339 snd_printk(KERN_ERR
2340 "%s: No available DAC for pin 0x%x\n",
2341 __func__, nid);
2342 return -ENODEV;
2343 }
2344
2345 spec->multiout.dac_nids[i] = conn[j];
2346 spec->multiout.num_dacs++;
2347 if (conn_len > 1) {
2348 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002349 snd_hda_codec_write_cache(codec, nid, 0,
2350 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002351
2352 }
Mattc7d4b2f2005-06-27 14:59:41 +02002353 }
2354
Steve Longerbeam7b043892007-05-03 20:50:03 +02002355 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2356 spec->multiout.num_dacs,
2357 spec->multiout.dac_nids[0],
2358 spec->multiout.dac_nids[1],
2359 spec->multiout.dac_nids[2],
2360 spec->multiout.dac_nids[3],
2361 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002362 return 0;
2363}
2364
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002365/* create volume control/switch for the given prefx type */
2366static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2367{
2368 char name[32];
2369 int err;
2370
2371 sprintf(name, "%s Playback Volume", pfx);
2372 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2373 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2374 if (err < 0)
2375 return err;
2376 sprintf(name, "%s Playback Switch", pfx);
2377 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2378 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2379 if (err < 0)
2380 return err;
2381 return 0;
2382}
2383
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002384static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2385{
2386 if (!spec->multiout.hp_nid)
2387 spec->multiout.hp_nid = nid;
2388 else if (spec->multiout.num_dacs > 4) {
2389 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2390 return 1;
2391 } else {
2392 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2393 spec->multiout.num_dacs++;
2394 }
2395 return 0;
2396}
2397
2398static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2399{
2400 if (is_in_dac_nids(spec, nid))
2401 return 1;
2402 if (spec->multiout.hp_nid == nid)
2403 return 1;
2404 return 0;
2405}
2406
Mattc7d4b2f2005-06-27 14:59:41 +02002407/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002408static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002409 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002410{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002411 static const char *chname[4] = {
2412 "Front", "Surround", NULL /*CLFE*/, "Side"
2413 };
Mattc7d4b2f2005-06-27 14:59:41 +02002414 hda_nid_t nid;
2415 int i, err;
2416
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002417 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002418 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002419
2420
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002421 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002422 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002423 continue;
2424
2425 nid = spec->multiout.dac_nids[i];
2426
2427 if (i == 2) {
2428 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002429 err = create_controls(spec, "Center", nid, 1);
2430 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002431 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002432 err = create_controls(spec, "LFE", nid, 2);
2433 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002434 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002435
2436 wid_caps = get_wcaps(codec, nid);
2437
2438 if (wid_caps & AC_WCAP_LR_SWAP) {
2439 err = stac92xx_add_control(spec,
2440 STAC_CTL_WIDGET_CLFE_SWITCH,
2441 "Swap Center/LFE Playback Switch", nid);
2442
2443 if (err < 0)
2444 return err;
2445 }
2446
Mattc7d4b2f2005-06-27 14:59:41 +02002447 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002448 err = create_controls(spec, chname[i], nid, 3);
2449 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002450 return err;
2451 }
2452 }
2453
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002454 if (cfg->hp_outs > 1) {
2455 err = stac92xx_add_control(spec,
2456 STAC_CTL_WIDGET_HP_SWITCH,
2457 "Headphone as Line Out Switch", 0);
2458 if (err < 0)
2459 return err;
2460 }
2461
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002462 if (spec->line_switch) {
2463 nid = cfg->input_pins[AUTO_PIN_LINE];
2464 pincap = snd_hda_param_read(codec, nid,
2465 AC_PAR_PIN_CAP);
2466 if (pincap & AC_PINCAP_OUT) {
2467 err = stac92xx_add_control(spec,
2468 STAC_CTL_WIDGET_IO_SWITCH,
2469 "Line In as Output Switch", nid << 8);
2470 if (err < 0)
2471 return err;
2472 }
2473 }
Matt Porter403d1942005-11-29 15:00:51 +01002474
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002475 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002476 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002477 unsigned int mic_pin = AUTO_PIN_MIC;
2478again:
2479 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002480 def_conf = snd_hda_codec_read(codec, nid, 0,
2481 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002482 /* some laptops have an internal analog microphone
2483 * which can't be used as a output */
2484 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2485 pincap = snd_hda_param_read(codec, nid,
2486 AC_PAR_PIN_CAP);
2487 if (pincap & AC_PINCAP_OUT) {
2488 err = stac92xx_add_control(spec,
2489 STAC_CTL_WIDGET_IO_SWITCH,
2490 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002491 nid = snd_hda_codec_read(codec, nid, 0,
2492 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2493 if (!check_in_dac_nids(spec, nid))
2494 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002495 if (err < 0)
2496 return err;
2497 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002498 } else if (mic_pin == AUTO_PIN_MIC) {
2499 mic_pin = AUTO_PIN_FRONT_MIC;
2500 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002501 }
2502 }
Matt Porter403d1942005-11-29 15:00:51 +01002503
Mattc7d4b2f2005-06-27 14:59:41 +02002504 return 0;
2505}
2506
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002507/* add playback controls for Speaker and HP outputs */
2508static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2509 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002510{
2511 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002512 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002513 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002514
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002515 old_num_dacs = spec->multiout.num_dacs;
2516 for (i = 0; i < cfg->hp_outs; i++) {
2517 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2518 if (wid_caps & AC_WCAP_UNSOL_CAP)
2519 spec->hp_detect = 1;
2520 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2521 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2522 if (check_in_dac_nids(spec, nid))
2523 nid = 0;
2524 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002525 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002526 add_spec_dacs(spec, nid);
2527 }
2528 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002529 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002530 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2531 if (check_in_dac_nids(spec, nid))
2532 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002533 if (! nid)
2534 continue;
2535 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002536 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002537 for (i = 0; i < cfg->line_outs; i++) {
2538 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2539 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2540 if (check_in_dac_nids(spec, nid))
2541 nid = 0;
2542 if (! nid)
2543 continue;
2544 add_spec_dacs(spec, nid);
2545 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002546 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2547 static const char *pfxs[] = {
2548 "Speaker", "External Speaker", "Speaker2",
2549 };
2550 err = create_controls(spec, pfxs[i - old_num_dacs],
2551 spec->multiout.dac_nids[i], 3);
2552 if (err < 0)
2553 return err;
2554 }
2555 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002556 err = create_controls(spec, "Headphone",
2557 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002558 if (err < 0)
2559 return err;
2560 }
Mattc7d4b2f2005-06-27 14:59:41 +02002561
2562 return 0;
2563}
2564
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002565/* labels for mono mux outputs */
2566static const char *stac92xx_mono_labels[3] = {
2567 "DAC0", "DAC1", "Mixer"
2568};
2569
2570/* create mono mux for mono out on capable codecs */
2571static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2572{
2573 struct sigmatel_spec *spec = codec->spec;
2574 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2575 int i, num_cons;
2576 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2577
2578 num_cons = snd_hda_get_connections(codec,
2579 spec->mono_nid,
2580 con_lst,
2581 HDA_MAX_NUM_INPUTS);
2582 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2583 return -EINVAL;
2584
2585 for (i = 0; i < num_cons; i++) {
2586 mono_mux->items[mono_mux->num_items].label =
2587 stac92xx_mono_labels[i];
2588 mono_mux->items[mono_mux->num_items].index = i;
2589 mono_mux->num_items++;
2590 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002591
2592 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2593 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002594}
2595
Matt Porter8b657272006-10-26 17:12:59 +02002596/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002597static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002598 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2599 "Digital Mic 3", "Digital Mic 4"
2600};
2601
2602/* create playback/capture controls for input pins on dmic capable codecs */
2603static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2604 const struct auto_pin_cfg *cfg)
2605{
2606 struct sigmatel_spec *spec = codec->spec;
2607 struct hda_input_mux *dimux = &spec->private_dimux;
2608 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002609 int err, i, j;
2610 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002611
2612 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2613 dimux->items[dimux->num_items].index = 0;
2614 dimux->num_items++;
2615
2616 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002617 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002618 int index;
2619 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002620 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002621 unsigned int def_conf;
2622
2623 def_conf = snd_hda_codec_read(codec,
2624 spec->dmic_nids[i],
2625 0,
2626 AC_VERB_GET_CONFIG_DEFAULT,
2627 0);
2628 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2629 continue;
2630
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002631 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002632 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002633 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002634 con_lst,
2635 HDA_MAX_NUM_INPUTS);
2636 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002637 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002638 index = j;
2639 goto found;
2640 }
2641 continue;
2642found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002643 wcaps = get_wcaps(codec, nid);
2644
2645 if (wcaps & AC_WCAP_OUT_AMP) {
2646 sprintf(name, "%s Capture Volume",
2647 stac92xx_dmic_labels[dimux->num_items]);
2648
2649 err = stac92xx_add_control(spec,
2650 STAC_CTL_WIDGET_VOL,
2651 name,
2652 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2653 if (err < 0)
2654 return err;
2655 }
2656
Matt Porter8b657272006-10-26 17:12:59 +02002657 dimux->items[dimux->num_items].label =
2658 stac92xx_dmic_labels[dimux->num_items];
2659 dimux->items[dimux->num_items].index = index;
2660 dimux->num_items++;
2661 }
2662
2663 return 0;
2664}
2665
Mattc7d4b2f2005-06-27 14:59:41 +02002666/* create playback/capture controls for input pins */
2667static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2668{
2669 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002670 struct hda_input_mux *imux = &spec->private_imux;
2671 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2672 int i, j, k;
2673
2674 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002675 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002676
Takashi Iwai314634b2006-09-21 11:56:18 +02002677 if (!cfg->input_pins[i])
2678 continue;
2679 index = -1;
2680 for (j = 0; j < spec->num_muxes; j++) {
2681 int num_cons;
2682 num_cons = snd_hda_get_connections(codec,
2683 spec->mux_nids[j],
2684 con_lst,
2685 HDA_MAX_NUM_INPUTS);
2686 for (k = 0; k < num_cons; k++)
2687 if (con_lst[k] == cfg->input_pins[i]) {
2688 index = k;
2689 goto found;
2690 }
Mattc7d4b2f2005-06-27 14:59:41 +02002691 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002692 continue;
2693 found:
2694 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2695 imux->items[imux->num_items].index = index;
2696 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002697 }
2698
Steve Longerbeam7b043892007-05-03 20:50:03 +02002699 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002700 /*
2701 * Set the current input for the muxes.
2702 * The STAC9221 has two input muxes with identical source
2703 * NID lists. Hopefully this won't get confused.
2704 */
2705 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002706 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2707 AC_VERB_SET_CONNECT_SEL,
2708 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002709 }
2710 }
2711
Mattc7d4b2f2005-06-27 14:59:41 +02002712 return 0;
2713}
2714
Mattc7d4b2f2005-06-27 14:59:41 +02002715static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2716{
2717 struct sigmatel_spec *spec = codec->spec;
2718 int i;
2719
2720 for (i = 0; i < spec->autocfg.line_outs; i++) {
2721 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2722 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2723 }
2724}
2725
2726static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2727{
2728 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002729 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002730
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002731 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2732 hda_nid_t pin;
2733 pin = spec->autocfg.hp_pins[i];
2734 if (pin) /* connect to front */
2735 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2736 }
2737 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2738 hda_nid_t pin;
2739 pin = spec->autocfg.speaker_pins[i];
2740 if (pin) /* connect to front */
2741 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2742 }
Mattc7d4b2f2005-06-27 14:59:41 +02002743}
2744
Matt Porter3cc08dc2006-01-23 15:27:49 +01002745static 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 +02002746{
2747 struct sigmatel_spec *spec = codec->spec;
2748 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002749 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002750
Matt Porter8b657272006-10-26 17:12:59 +02002751 if ((err = snd_hda_parse_pin_def_config(codec,
2752 &spec->autocfg,
2753 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002754 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002755 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002756 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002757
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002758 /* If we have no real line-out pin and multiple hp-outs, HPs should
2759 * be set up as multi-channel outputs.
2760 */
2761 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2762 spec->autocfg.hp_outs > 1) {
2763 /* Copy hp_outs to line_outs, backup line_outs in
2764 * speaker_outs so that the following routines can handle
2765 * HP pins as primary outputs.
2766 */
2767 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2768 sizeof(spec->autocfg.line_out_pins));
2769 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2770 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2771 sizeof(spec->autocfg.hp_pins));
2772 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2773 hp_speaker_swap = 1;
2774 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002775 if (spec->autocfg.mono_out_pin) {
2776 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2777 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2778 u32 caps = query_amp_caps(codec,
2779 spec->autocfg.mono_out_pin, dir);
2780 hda_nid_t conn_list[1];
2781
2782 /* get the mixer node and then the mono mux if it exists */
2783 if (snd_hda_get_connections(codec,
2784 spec->autocfg.mono_out_pin, conn_list, 1) &&
2785 snd_hda_get_connections(codec, conn_list[0],
2786 conn_list, 1)) {
2787
2788 int wcaps = get_wcaps(codec, conn_list[0]);
2789 int wid_type = (wcaps & AC_WCAP_TYPE)
2790 >> AC_WCAP_TYPE_SHIFT;
2791 /* LR swap check, some stac925x have a mux that
2792 * changes the DACs output path instead of the
2793 * mono-mux path.
2794 */
2795 if (wid_type == AC_WID_AUD_SEL &&
2796 !(wcaps & AC_WCAP_LR_SWAP))
2797 spec->mono_nid = conn_list[0];
2798 }
2799 /* all mono outs have a least a mute/unmute switch */
2800 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2801 "Mono Playback Switch",
2802 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2803 1, 0, dir));
2804 if (err < 0)
2805 return err;
2806 /* check to see if there is volume support for the amp */
2807 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2808 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2809 "Mono Playback Volume",
2810 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2811 1, 0, dir));
2812 if (err < 0)
2813 return err;
2814 }
2815
2816 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2817 AC_PINCTL_OUT_EN);
2818 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002819
Matt Porter403d1942005-11-29 15:00:51 +01002820 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2821 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002822 if (spec->multiout.num_dacs == 0)
2823 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2824 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002825
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002826 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2827
2828 if (err < 0)
2829 return err;
2830
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002831 if (hp_speaker_swap == 1) {
2832 /* Restore the hp_outs and line_outs */
2833 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2834 sizeof(spec->autocfg.line_out_pins));
2835 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2836 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2837 sizeof(spec->autocfg.speaker_pins));
2838 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2839 memset(spec->autocfg.speaker_pins, 0,
2840 sizeof(spec->autocfg.speaker_pins));
2841 spec->autocfg.speaker_outs = 0;
2842 }
2843
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002844 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2845
2846 if (err < 0)
2847 return err;
2848
2849 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2850
2851 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002852 return err;
2853
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002854 if (spec->mono_nid > 0) {
2855 err = stac92xx_auto_create_mono_output_ctls(codec);
2856 if (err < 0)
2857 return err;
2858 }
2859
Matt Porter8b657272006-10-26 17:12:59 +02002860 if (spec->num_dmics > 0)
2861 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2862 &spec->autocfg)) < 0)
2863 return err;
2864
Mattc7d4b2f2005-06-27 14:59:41 +02002865 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002866 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002867 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002868
Takashi Iwai82bc9552006-03-21 11:24:42 +01002869 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002870 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002871 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002872 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002873
2874 if (spec->kctl_alloc)
2875 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2876
2877 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002878 if (!spec->dinput_mux)
2879 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002880 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002881
2882 return 1;
2883}
2884
Takashi Iwai82bc9552006-03-21 11:24:42 +01002885/* add playback controls for HP output */
2886static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2887 struct auto_pin_cfg *cfg)
2888{
2889 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002890 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002891 unsigned int wid_caps;
2892
2893 if (! pin)
2894 return 0;
2895
2896 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002897 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002898 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002899
2900 return 0;
2901}
2902
Richard Fish160ea0d2006-09-06 13:58:25 +02002903/* add playback controls for LFE output */
2904static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2905 struct auto_pin_cfg *cfg)
2906{
2907 struct sigmatel_spec *spec = codec->spec;
2908 int err;
2909 hda_nid_t lfe_pin = 0x0;
2910 int i;
2911
2912 /*
2913 * search speaker outs and line outs for a mono speaker pin
2914 * with an amp. If one is found, add LFE controls
2915 * for it.
2916 */
2917 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2918 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002919 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002920 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2921 if (wcaps == AC_WCAP_OUT_AMP)
2922 /* found a mono speaker with an amp, must be lfe */
2923 lfe_pin = pin;
2924 }
2925
2926 /* if speaker_outs is 0, then speakers may be in line_outs */
2927 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2928 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2929 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002930 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01002931 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02002932 AC_VERB_GET_CONFIG_DEFAULT,
2933 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01002934 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002935 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002936 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2937 if (wcaps == AC_WCAP_OUT_AMP)
2938 /* found a mono speaker with an amp,
2939 must be lfe */
2940 lfe_pin = pin;
2941 }
2942 }
2943 }
2944
2945 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002946 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002947 if (err < 0)
2948 return err;
2949 }
2950
2951 return 0;
2952}
2953
Mattc7d4b2f2005-06-27 14:59:41 +02002954static int stac9200_parse_auto_config(struct hda_codec *codec)
2955{
2956 struct sigmatel_spec *spec = codec->spec;
2957 int err;
2958
Kailang Yangdf694da2005-12-05 19:42:22 +01002959 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002960 return err;
2961
2962 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2963 return err;
2964
Takashi Iwai82bc9552006-03-21 11:24:42 +01002965 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2966 return err;
2967
Richard Fish160ea0d2006-09-06 13:58:25 +02002968 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2969 return err;
2970
Takashi Iwai82bc9552006-03-21 11:24:42 +01002971 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002972 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002973 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002974 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002975
2976 if (spec->kctl_alloc)
2977 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2978
2979 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002980 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002981
2982 return 1;
2983}
2984
Sam Revitch62fe78e2006-05-10 15:09:17 +02002985/*
2986 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2987 * funky external mute control using GPIO pins.
2988 */
2989
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002990static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002991 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002992{
2993 unsigned int gpiostate, gpiomask, gpiodir;
2994
2995 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2996 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002997 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002998
2999 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3000 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003001 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003002
3003 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3004 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003005 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003006
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003007 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003008 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3009
3010 snd_hda_codec_write(codec, codec->afg, 0,
3011 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003012 snd_hda_codec_read(codec, codec->afg, 0,
3013 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003014
3015 msleep(1);
3016
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003017 snd_hda_codec_read(codec, codec->afg, 0,
3018 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003019}
3020
Takashi Iwai314634b2006-09-21 11:56:18 +02003021static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3022 unsigned int event)
3023{
3024 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003025 snd_hda_codec_write_cache(codec, nid, 0,
3026 AC_VERB_SET_UNSOLICITED_ENABLE,
3027 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003028}
3029
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003030static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3031{
3032 int i;
3033 for (i = 0; i < cfg->hp_outs; i++)
3034 if (cfg->hp_pins[i] == nid)
3035 return 1; /* nid is a HP-Out */
3036
3037 return 0; /* nid is not a HP-Out */
3038};
3039
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003040static void stac92xx_power_down(struct hda_codec *codec)
3041{
3042 struct sigmatel_spec *spec = codec->spec;
3043
3044 /* power down inactive DACs */
3045 hda_nid_t *dac;
3046 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003047 if (!is_in_dac_nids(spec, *dac) &&
3048 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003049 snd_hda_codec_write_cache(codec, *dac, 0,
3050 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3051}
3052
Mattc7d4b2f2005-06-27 14:59:41 +02003053static int stac92xx_init(struct hda_codec *codec)
3054{
3055 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003056 struct auto_pin_cfg *cfg = &spec->autocfg;
3057 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003058
Mattc7d4b2f2005-06-27 14:59:41 +02003059 snd_hda_sequence_write(codec, spec->init);
3060
Takashi Iwai82bc9552006-03-21 11:24:42 +01003061 /* set up pins */
3062 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003063 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003064 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003065 enable_pin_detect(codec, cfg->hp_pins[i],
3066 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003067 /* force to enable the first line-out; the others are set up
3068 * in unsol_event
3069 */
3070 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3071 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003072 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003073 /* fake event to set up pins */
3074 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3075 } else {
3076 stac92xx_auto_init_multi_out(codec);
3077 stac92xx_auto_init_hp_out(codec);
3078 }
3079 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003080 hda_nid_t nid = cfg->input_pins[i];
3081 if (nid) {
3082 unsigned int pinctl = AC_PINCTL_IN_EN;
3083 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3084 pinctl |= stac92xx_get_vref(codec, nid);
3085 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3086 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003087 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003088 for (i = 0; i < spec->num_dmics; i++)
3089 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3090 AC_PINCTL_IN_EN);
3091 for (i = 0; i < spec->num_pwrs; i++) {
3092 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3093 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3094 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3095 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003096 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3097 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003098 /* outputs are only ports capable of power management
3099 * any attempts on powering down a input port cause the
3100 * referenced VREF to act quirky.
3101 */
3102 if (pinctl & AC_PINCTL_IN_EN)
3103 continue;
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003104 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
3105 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003106 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3107 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3108 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003109 if (spec->dac_list)
3110 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003111 if (cfg->dig_out_pin)
3112 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3113 AC_PINCTL_OUT_EN);
3114 if (cfg->dig_in_pin)
3115 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3116 AC_PINCTL_IN_EN);
3117
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003118 stac_gpio_set(codec, spec->gpio_mask,
3119 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003120
Mattc7d4b2f2005-06-27 14:59:41 +02003121 return 0;
3122}
3123
Matt2f2f4252005-04-13 14:45:30 +02003124static void stac92xx_free(struct hda_codec *codec)
3125{
Mattc7d4b2f2005-06-27 14:59:41 +02003126 struct sigmatel_spec *spec = codec->spec;
3127 int i;
3128
3129 if (! spec)
3130 return;
3131
3132 if (spec->kctl_alloc) {
3133 for (i = 0; i < spec->num_kctl_used; i++)
3134 kfree(spec->kctl_alloc[i].name);
3135 kfree(spec->kctl_alloc);
3136 }
3137
Richard Fish11b44bb2006-08-23 18:31:34 +02003138 if (spec->bios_pin_configs)
3139 kfree(spec->bios_pin_configs);
3140
Mattc7d4b2f2005-06-27 14:59:41 +02003141 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02003142}
3143
Matt4e550962005-07-04 17:51:39 +02003144static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3145 unsigned int flag)
3146{
3147 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3148 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003149
Takashi Iwaif9acba42007-05-29 18:01:06 +02003150 if (pin_ctl & AC_PINCTL_IN_EN) {
3151 /*
3152 * we need to check the current set-up direction of
3153 * shared input pins since they can be switched via
3154 * "xxx as Output" mixer switch
3155 */
3156 struct sigmatel_spec *spec = codec->spec;
3157 struct auto_pin_cfg *cfg = &spec->autocfg;
3158 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3159 spec->line_switch) ||
3160 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3161 spec->mic_switch))
3162 return;
3163 }
3164
Steve Longerbeam7b043892007-05-03 20:50:03 +02003165 /* if setting pin direction bits, clear the current
3166 direction bits first */
3167 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3168 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3169
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003170 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003171 AC_VERB_SET_PIN_WIDGET_CONTROL,
3172 pin_ctl | flag);
3173}
3174
3175static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3176 unsigned int flag)
3177{
3178 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3179 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003180 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003181 AC_VERB_SET_PIN_WIDGET_CONTROL,
3182 pin_ctl & ~flag);
3183}
3184
Jiang Zhe40c1d302007-11-12 13:05:16 +01003185static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003186{
3187 if (!nid)
3188 return 0;
3189 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003190 & (1 << 31)) {
3191 unsigned int pinctl;
3192 pinctl = snd_hda_codec_read(codec, nid, 0,
3193 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3194 if (pinctl & AC_PINCTL_IN_EN)
3195 return 0; /* mic- or line-input */
3196 else
3197 return 1; /* HP-output */
3198 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003199 return 0;
3200}
3201
3202static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003203{
3204 struct sigmatel_spec *spec = codec->spec;
3205 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003206 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003207 int i, presence;
3208
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003209 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003210 if (spec->gpio_mute)
3211 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3212 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3213
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003214 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003215 if (presence)
3216 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003217 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3218 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003219 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003220 }
Matt4e550962005-07-04 17:51:39 +02003221
3222 if (presence) {
3223 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003224 if (spec->hp_switch)
3225 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003226 for (i = 0; i < cfg->line_outs; i++)
3227 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3228 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003229 for (i = 0; i < cfg->speaker_outs; i++)
3230 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3231 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003232 if (spec->eapd_mask)
3233 stac_gpio_set(codec, spec->gpio_mask,
3234 spec->gpio_dir, spec->gpio_data &
3235 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003236 } else {
3237 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003238 if (spec->hp_switch)
3239 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003240 for (i = 0; i < cfg->line_outs; i++)
3241 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3242 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003243 for (i = 0; i < cfg->speaker_outs; i++)
3244 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3245 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003246 if (spec->eapd_mask)
3247 stac_gpio_set(codec, spec->gpio_mask,
3248 spec->gpio_dir, spec->gpio_data |
3249 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003250 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003251 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3252 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003253}
3254
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003255static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3256{
3257 struct sigmatel_spec *spec = codec->spec;
3258 hda_nid_t nid = spec->pwr_nids[idx];
3259 int presence, val;
3260 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3261 & 0x000000ff;
3262 presence = get_hp_pin_presence(codec, nid);
3263 idx = 1 << idx;
3264
3265 if (presence)
3266 val &= ~idx;
3267 else
3268 val |= idx;
3269
3270 /* power down unused output ports */
3271 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3272};
3273
Takashi Iwai314634b2006-09-21 11:56:18 +02003274static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3275{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003276 struct sigmatel_spec *spec = codec->spec;
3277 int idx = res >> 26 & 0x0f;
3278
3279 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003280 case STAC_HP_EVENT:
3281 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003282 /* fallthru */
3283 case STAC_PWR_EVENT:
3284 if (spec->num_pwrs > 0)
3285 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003286 }
3287}
3288
Takashi Iwaicb53c622007-08-10 17:21:45 +02003289#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003290static int stac92xx_resume(struct hda_codec *codec)
3291{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003292 struct sigmatel_spec *spec = codec->spec;
3293
Richard Fish11b44bb2006-08-23 18:31:34 +02003294 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003295 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003296 stac_gpio_set(codec, spec->gpio_mask,
3297 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003298 snd_hda_codec_resume_amp(codec);
3299 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003300 /* power down inactive DACs */
3301 if (spec->dac_list)
3302 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003303 /* invoke unsolicited event to reset the HP state */
3304 if (spec->hp_detect)
3305 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003306 return 0;
3307}
3308#endif
3309
Matt2f2f4252005-04-13 14:45:30 +02003310static struct hda_codec_ops stac92xx_patch_ops = {
3311 .build_controls = stac92xx_build_controls,
3312 .build_pcms = stac92xx_build_pcms,
3313 .init = stac92xx_init,
3314 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003315 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003316#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003317 .resume = stac92xx_resume,
3318#endif
Matt2f2f4252005-04-13 14:45:30 +02003319};
3320
3321static int patch_stac9200(struct hda_codec *codec)
3322{
3323 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003324 int err;
Matt2f2f4252005-04-13 14:45:30 +02003325
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003326 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003327 if (spec == NULL)
3328 return -ENOMEM;
3329
3330 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003331 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003332 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003333 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3334 stac9200_models,
3335 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003336 if (spec->board_config < 0) {
3337 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3338 err = stac92xx_save_bios_config_regs(codec);
3339 if (err < 0) {
3340 stac92xx_free(codec);
3341 return err;
3342 }
3343 spec->pin_configs = spec->bios_pin_configs;
3344 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003345 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3346 stac92xx_set_config_regs(codec);
3347 }
Matt2f2f4252005-04-13 14:45:30 +02003348
3349 spec->multiout.max_channels = 2;
3350 spec->multiout.num_dacs = 1;
3351 spec->multiout.dac_nids = stac9200_dac_nids;
3352 spec->adc_nids = stac9200_adc_nids;
3353 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003354 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003355 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003356 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003357 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003358
Tobin Davisbf277782008-02-03 20:31:47 +01003359 if (spec->board_config == STAC_9200_GATEWAY ||
3360 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003361 spec->init = stac9200_eapd_init;
3362 else
3363 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003364 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003365
Takashi Iwai117f2572008-03-18 09:53:23 +01003366 if (spec->board_config == STAC_9200_PANASONIC) {
3367 spec->gpio_mask = spec->gpio_dir = 0x09;
3368 spec->gpio_data = 0x00;
3369 }
3370
Mattc7d4b2f2005-06-27 14:59:41 +02003371 err = stac9200_parse_auto_config(codec);
3372 if (err < 0) {
3373 stac92xx_free(codec);
3374 return err;
3375 }
Matt2f2f4252005-04-13 14:45:30 +02003376
3377 codec->patch_ops = stac92xx_patch_ops;
3378
3379 return 0;
3380}
3381
Tobin Davis8e21c342007-01-08 11:04:17 +01003382static int patch_stac925x(struct hda_codec *codec)
3383{
3384 struct sigmatel_spec *spec;
3385 int err;
3386
3387 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3388 if (spec == NULL)
3389 return -ENOMEM;
3390
3391 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003392 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003393 spec->pin_nids = stac925x_pin_nids;
3394 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3395 stac925x_models,
3396 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003397 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003398 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003399 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3400 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003401 err = stac92xx_save_bios_config_regs(codec);
3402 if (err < 0) {
3403 stac92xx_free(codec);
3404 return err;
3405 }
3406 spec->pin_configs = spec->bios_pin_configs;
3407 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3408 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3409 stac92xx_set_config_regs(codec);
3410 }
3411
3412 spec->multiout.max_channels = 2;
3413 spec->multiout.num_dacs = 1;
3414 spec->multiout.dac_nids = stac925x_dac_nids;
3415 spec->adc_nids = stac925x_adc_nids;
3416 spec->mux_nids = stac925x_mux_nids;
3417 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003418 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003419 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003420 switch (codec->vendor_id) {
3421 case 0x83847632: /* STAC9202 */
3422 case 0x83847633: /* STAC9202D */
3423 case 0x83847636: /* STAC9251 */
3424 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003425 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003426 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003427 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3428 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003429 break;
3430 default:
3431 spec->num_dmics = 0;
3432 break;
3433 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003434
3435 spec->init = stac925x_core_init;
3436 spec->mixer = stac925x_mixer;
3437
3438 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003439 if (!err) {
3440 if (spec->board_config < 0) {
3441 printk(KERN_WARNING "hda_codec: No auto-config is "
3442 "available, default to model=ref\n");
3443 spec->board_config = STAC_925x_REF;
3444 goto again;
3445 }
3446 err = -EINVAL;
3447 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003448 if (err < 0) {
3449 stac92xx_free(codec);
3450 return err;
3451 }
3452
3453 codec->patch_ops = stac92xx_patch_ops;
3454
3455 return 0;
3456}
3457
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003458static struct hda_input_mux stac92hd73xx_dmux = {
3459 .num_items = 4,
3460 .items = {
3461 { "Analog Inputs", 0x0b },
3462 { "CD", 0x08 },
3463 { "Digital Mic 1", 0x09 },
3464 { "Digital Mic 2", 0x0a },
3465 }
3466};
3467
3468static int patch_stac92hd73xx(struct hda_codec *codec)
3469{
3470 struct sigmatel_spec *spec;
3471 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3472 int err = 0;
3473
3474 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3475 if (spec == NULL)
3476 return -ENOMEM;
3477
3478 codec->spec = spec;
3479 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3480 spec->pin_nids = stac92hd73xx_pin_nids;
3481 spec->board_config = snd_hda_check_board_config(codec,
3482 STAC_92HD73XX_MODELS,
3483 stac92hd73xx_models,
3484 stac92hd73xx_cfg_tbl);
3485again:
3486 if (spec->board_config < 0) {
3487 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3488 " STAC92HD73XX, using BIOS defaults\n");
3489 err = stac92xx_save_bios_config_regs(codec);
3490 if (err < 0) {
3491 stac92xx_free(codec);
3492 return err;
3493 }
3494 spec->pin_configs = spec->bios_pin_configs;
3495 } else {
3496 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3497 stac92xx_set_config_regs(codec);
3498 }
3499
3500 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3501 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3502
3503 if (spec->multiout.num_dacs < 0) {
3504 printk(KERN_WARNING "hda_codec: Could not determine "
3505 "number of channels defaulting to DAC count\n");
3506 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3507 }
3508
3509 switch (spec->multiout.num_dacs) {
3510 case 0x3: /* 6 Channel */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003511 spec->multiout.hp_nid = 0x17;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003512 spec->mixer = stac92hd73xx_6ch_mixer;
3513 spec->init = stac92hd73xx_6ch_core_init;
3514 break;
3515 case 0x4: /* 8 Channel */
3516 spec->multiout.hp_nid = 0x18;
3517 spec->mixer = stac92hd73xx_8ch_mixer;
3518 spec->init = stac92hd73xx_8ch_core_init;
3519 break;
3520 case 0x5: /* 10 Channel */
3521 spec->multiout.hp_nid = 0x19;
3522 spec->mixer = stac92hd73xx_10ch_mixer;
3523 spec->init = stac92hd73xx_10ch_core_init;
3524 };
3525
3526 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3527 spec->aloopback_mask = 0x01;
3528 spec->aloopback_shift = 8;
3529
3530 spec->mux_nids = stac92hd73xx_mux_nids;
3531 spec->adc_nids = stac92hd73xx_adc_nids;
3532 spec->dmic_nids = stac92hd73xx_dmic_nids;
3533 spec->dmux_nids = stac92hd73xx_dmux_nids;
3534
3535 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3536 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003537 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003538 spec->dinput_mux = &stac92hd73xx_dmux;
3539 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003540 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003541 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003542
Matthew Ranostaya7662642008-02-21 07:51:14 +01003543 switch (spec->board_config) {
3544 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003545 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003546 switch (codec->subsystem_id) {
3547 case 0x1028025e: /* Analog Mics */
3548 case 0x1028025f:
3549 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3550 spec->num_dmics = 0;
3551 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003552 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003553 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003554 spec->init = dell_m6_core_init;
3555 /* fall-through */
3556 case 0x10280254:
3557 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003558 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3559 spec->num_dmics = 1;
3560 break;
3561 case 0x10280256: /* Both */
3562 case 0x10280057:
3563 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3564 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3565 spec->num_dmics = 1;
3566 break;
3567 }
3568 break;
3569 default:
3570 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3571 }
3572
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003573 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3574 spec->pwr_nids = stac92hd73xx_pwr_nids;
3575
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003576 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3577
3578 if (!err) {
3579 if (spec->board_config < 0) {
3580 printk(KERN_WARNING "hda_codec: No auto-config is "
3581 "available, default to model=ref\n");
3582 spec->board_config = STAC_92HD73XX_REF;
3583 goto again;
3584 }
3585 err = -EINVAL;
3586 }
3587
3588 if (err < 0) {
3589 stac92xx_free(codec);
3590 return err;
3591 }
3592
3593 codec->patch_ops = stac92xx_patch_ops;
3594
3595 return 0;
3596}
3597
Matthew Ranostaye035b842007-11-06 11:53:55 +01003598static int patch_stac92hd71bxx(struct hda_codec *codec)
3599{
3600 struct sigmatel_spec *spec;
3601 int err = 0;
3602
3603 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3604 if (spec == NULL)
3605 return -ENOMEM;
3606
3607 codec->spec = spec;
3608 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3609 spec->pin_nids = stac92hd71bxx_pin_nids;
3610 spec->board_config = snd_hda_check_board_config(codec,
3611 STAC_92HD71BXX_MODELS,
3612 stac92hd71bxx_models,
3613 stac92hd71bxx_cfg_tbl);
3614again:
3615 if (spec->board_config < 0) {
3616 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3617 " STAC92HD71BXX, using BIOS defaults\n");
3618 err = stac92xx_save_bios_config_regs(codec);
3619 if (err < 0) {
3620 stac92xx_free(codec);
3621 return err;
3622 }
3623 spec->pin_configs = spec->bios_pin_configs;
3624 } else {
3625 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3626 stac92xx_set_config_regs(codec);
3627 }
3628
Matthew Ranostay541eee82007-12-14 12:08:04 +01003629 switch (codec->vendor_id) {
3630 case 0x111d76b6: /* 4 Port without Analog Mixer */
3631 case 0x111d76b7:
3632 case 0x111d76b4: /* 6 Port without Analog Mixer */
3633 case 0x111d76b5:
3634 spec->mixer = stac92hd71bxx_mixer;
3635 spec->init = stac92hd71bxx_core_init;
3636 break;
3637 default:
3638 spec->mixer = stac92hd71bxx_analog_mixer;
3639 spec->init = stac92hd71bxx_analog_core_init;
3640 }
3641
3642 spec->aloopback_mask = 0x20;
3643 spec->aloopback_shift = 0;
3644
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003645 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003646 spec->gpio_mask = 0x01;
3647 spec->gpio_dir = 0x01;
3648 spec->gpio_mask = 0x01;
3649 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003650
Matthew Ranostaye035b842007-11-06 11:53:55 +01003651 spec->mux_nids = stac92hd71bxx_mux_nids;
3652 spec->adc_nids = stac92hd71bxx_adc_nids;
3653 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003654 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003655
3656 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3657 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3658 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003659 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003660
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003661 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3662 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3663
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01003664 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003665 spec->multiout.hp_nid = 0x11;
3666 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3667
3668 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3669 if (!err) {
3670 if (spec->board_config < 0) {
3671 printk(KERN_WARNING "hda_codec: No auto-config is "
3672 "available, default to model=ref\n");
3673 spec->board_config = STAC_92HD71BXX_REF;
3674 goto again;
3675 }
3676 err = -EINVAL;
3677 }
3678
3679 if (err < 0) {
3680 stac92xx_free(codec);
3681 return err;
3682 }
3683
3684 codec->patch_ops = stac92xx_patch_ops;
3685
3686 return 0;
3687};
3688
Matt2f2f4252005-04-13 14:45:30 +02003689static int patch_stac922x(struct hda_codec *codec)
3690{
3691 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003692 int err;
Matt2f2f4252005-04-13 14:45:30 +02003693
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003694 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003695 if (spec == NULL)
3696 return -ENOMEM;
3697
3698 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003699 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003700 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003701 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3702 stac922x_models,
3703 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003704 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003705 spec->gpio_mask = spec->gpio_dir = 0x03;
3706 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003707 /* Intel Macs have all same PCI SSID, so we need to check
3708 * codec SSID to distinguish the exact models
3709 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003710 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003711 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003712
3713 case 0x106b0800:
3714 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003715 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003716 case 0x106b0600:
3717 case 0x106b0700:
3718 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003719 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003720 case 0x106b0e00:
3721 case 0x106b0f00:
3722 case 0x106b1600:
3723 case 0x106b1700:
3724 case 0x106b0200:
3725 case 0x106b1e00:
3726 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003727 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003728 case 0x106b1a00:
3729 case 0x00000100:
3730 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003731 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003732 case 0x106b0a00:
3733 case 0x106b2200:
3734 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003735 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003736 }
3737 }
3738
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003739 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003740 if (spec->board_config < 0) {
3741 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3742 "using BIOS defaults\n");
3743 err = stac92xx_save_bios_config_regs(codec);
3744 if (err < 0) {
3745 stac92xx_free(codec);
3746 return err;
3747 }
3748 spec->pin_configs = spec->bios_pin_configs;
3749 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003750 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3751 stac92xx_set_config_regs(codec);
3752 }
Matt2f2f4252005-04-13 14:45:30 +02003753
Matt2f2f4252005-04-13 14:45:30 +02003754 spec->adc_nids = stac922x_adc_nids;
3755 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003756 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003757 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003758 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003759 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003760
3761 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003762 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003763
3764 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003765
Matt Porter3cc08dc2006-01-23 15:27:49 +01003766 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003767 if (!err) {
3768 if (spec->board_config < 0) {
3769 printk(KERN_WARNING "hda_codec: No auto-config is "
3770 "available, default to model=ref\n");
3771 spec->board_config = STAC_D945_REF;
3772 goto again;
3773 }
3774 err = -EINVAL;
3775 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003776 if (err < 0) {
3777 stac92xx_free(codec);
3778 return err;
3779 }
3780
3781 codec->patch_ops = stac92xx_patch_ops;
3782
Takashi Iwai807a46362007-05-29 19:01:37 +02003783 /* Fix Mux capture level; max to 2 */
3784 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3785 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3786 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3787 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3788 (0 << AC_AMPCAP_MUTE_SHIFT));
3789
Matt Porter3cc08dc2006-01-23 15:27:49 +01003790 return 0;
3791}
3792
3793static int patch_stac927x(struct hda_codec *codec)
3794{
3795 struct sigmatel_spec *spec;
3796 int err;
3797
3798 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3799 if (spec == NULL)
3800 return -ENOMEM;
3801
3802 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003803 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003804 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003805 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3806 stac927x_models,
3807 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003808 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003809 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3810 if (spec->board_config < 0)
3811 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3812 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003813 err = stac92xx_save_bios_config_regs(codec);
3814 if (err < 0) {
3815 stac92xx_free(codec);
3816 return err;
3817 }
3818 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003819 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003820 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3821 stac92xx_set_config_regs(codec);
3822 }
3823
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003824 spec->adc_nids = stac927x_adc_nids;
3825 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3826 spec->mux_nids = stac927x_mux_nids;
3827 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003828 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003829 spec->multiout.dac_nids = spec->dac_nids;
3830
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003831 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003832 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003833 case STAC_D965_5ST:
3834 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003835 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003836 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003837 spec->num_dmics = 0;
3838
Tobin Davis93ed1502006-09-01 21:03:12 +02003839 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003840 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003841 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003842 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02003843 switch (codec->subsystem_id) {
3844 case 0x10280209:
3845 case 0x1028022e:
3846 /* correct the device field to SPDIF out */
3847 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
3848 break;
3849 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003850 /* configure the analog microphone on some laptops */
3851 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003852 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003853 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003854 /* correct the front input jack as a mic */
3855 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3856 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003857 case STAC_DELL_3ST:
3858 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003859 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003860 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003861 spec->dmic_nids = stac927x_dmic_nids;
3862 spec->num_dmics = STAC927X_NUM_DMICS;
3863
Tobin Davis93ed1502006-09-01 21:03:12 +02003864 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003865 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003866 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003867 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003868 break;
3869 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003870 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003871 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003872 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003873 spec->num_dmics = 0;
3874
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003875 spec->init = stac927x_core_init;
3876 spec->mixer = stac927x_mixer;
3877 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003878
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003879 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003880 spec->aloopback_mask = 0x40;
3881 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003882
Matt Porter3cc08dc2006-01-23 15:27:49 +01003883 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003884 if (!err) {
3885 if (spec->board_config < 0) {
3886 printk(KERN_WARNING "hda_codec: No auto-config is "
3887 "available, default to model=ref\n");
3888 spec->board_config = STAC_D965_REF;
3889 goto again;
3890 }
3891 err = -EINVAL;
3892 }
Mattc7d4b2f2005-06-27 14:59:41 +02003893 if (err < 0) {
3894 stac92xx_free(codec);
3895 return err;
3896 }
Matt2f2f4252005-04-13 14:45:30 +02003897
3898 codec->patch_ops = stac92xx_patch_ops;
3899
Takashi Iwai52987652008-01-16 16:09:47 +01003900 /*
3901 * !!FIXME!!
3902 * The STAC927x seem to require fairly long delays for certain
3903 * command sequences. With too short delays (even if the answer
3904 * is set to RIRB properly), it results in the silence output
3905 * on some hardwares like Dell.
3906 *
3907 * The below flag enables the longer delay (see get_response
3908 * in hda_intel.c).
3909 */
3910 codec->bus->needs_damn_long_delay = 1;
3911
Matt2f2f4252005-04-13 14:45:30 +02003912 return 0;
3913}
3914
Matt Porterf3302a52006-07-31 12:49:34 +02003915static int patch_stac9205(struct hda_codec *codec)
3916{
3917 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003918 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003919
3920 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3921 if (spec == NULL)
3922 return -ENOMEM;
3923
3924 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003925 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003926 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003927 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3928 stac9205_models,
3929 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003930 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003931 if (spec->board_config < 0) {
3932 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3933 err = stac92xx_save_bios_config_regs(codec);
3934 if (err < 0) {
3935 stac92xx_free(codec);
3936 return err;
3937 }
3938 spec->pin_configs = spec->bios_pin_configs;
3939 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003940 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3941 stac92xx_set_config_regs(codec);
3942 }
3943
3944 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003945 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003946 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003947 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003948 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003949 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003950 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003951 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003952 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003953
3954 spec->init = stac9205_core_init;
3955 spec->mixer = stac9205_mixer;
3956
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003957 spec->aloopback_mask = 0x40;
3958 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003959 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003960
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003961 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003962 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003963 /* Enable SPDIF in/out */
3964 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3965 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003966
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003967 /* Enable unsol response for GPIO4/Dock HP connection */
3968 snd_hda_codec_write(codec, codec->afg, 0,
3969 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3970 snd_hda_codec_write_cache(codec, codec->afg, 0,
3971 AC_VERB_SET_UNSOLICITED_ENABLE,
3972 (AC_USRSP_EN | STAC_HP_EVENT));
3973
3974 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003975 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003976 spec->gpio_mask = 0x1b;
3977 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003978 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003979 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003980 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003981 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003982 break;
3983 default:
3984 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003985 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003986 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003987 break;
3988 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003989
Matt Porterf3302a52006-07-31 12:49:34 +02003990 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003991 if (!err) {
3992 if (spec->board_config < 0) {
3993 printk(KERN_WARNING "hda_codec: No auto-config is "
3994 "available, default to model=ref\n");
3995 spec->board_config = STAC_9205_REF;
3996 goto again;
3997 }
3998 err = -EINVAL;
3999 }
Matt Porterf3302a52006-07-31 12:49:34 +02004000 if (err < 0) {
4001 stac92xx_free(codec);
4002 return err;
4003 }
4004
4005 codec->patch_ops = stac92xx_patch_ops;
4006
4007 return 0;
4008}
4009
Matt2f2f4252005-04-13 14:45:30 +02004010/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004011 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004012 */
4013
Guillaume Munch99ccc562006-08-16 19:35:12 +02004014/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004015static hda_nid_t vaio_dacs[] = { 0x2 };
4016#define VAIO_HP_DAC 0x5
4017static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4018static hda_nid_t vaio_mux_nids[] = { 0x15 };
4019
4020static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004021 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004022 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004023 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004024 { "Mic Jack", 0x1 },
4025 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004026 { "PCM", 0x3 },
4027 }
4028};
4029
4030static struct hda_verb vaio_init[] = {
4031 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004032 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004033 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4034 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4035 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4036 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004037 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004038 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4039 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4040 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4041 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4042 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4043 {}
4044};
4045
Guillaume Munch6d859062006-08-22 17:15:47 +02004046static struct hda_verb vaio_ar_init[] = {
4047 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4048 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4049 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4050 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4051/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4052 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004053 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004054 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4055 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4056/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4057 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4058 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4059 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4060 {}
4061};
4062
Takashi Iwaidb064e52006-03-16 16:04:58 +01004063/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004064static struct hda_bind_ctls vaio_bind_master_vol = {
4065 .ops = &snd_hda_bind_vol,
4066 .values = {
4067 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4068 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4069 0
4070 },
4071};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004072
4073/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004074static struct hda_bind_ctls vaio_bind_master_sw = {
4075 .ops = &snd_hda_bind_sw,
4076 .values = {
4077 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4078 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4079 0,
4080 },
4081};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004082
4083static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004084 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4085 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004086 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4087 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4088 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4089 {
4090 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4091 .name = "Capture Source",
4092 .count = 1,
4093 .info = stac92xx_mux_enum_info,
4094 .get = stac92xx_mux_enum_get,
4095 .put = stac92xx_mux_enum_put,
4096 },
4097 {}
4098};
4099
Guillaume Munch6d859062006-08-22 17:15:47 +02004100static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004101 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4102 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004103 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4104 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4105 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4106 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4107 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4108 {
4109 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4110 .name = "Capture Source",
4111 .count = 1,
4112 .info = stac92xx_mux_enum_info,
4113 .get = stac92xx_mux_enum_get,
4114 .put = stac92xx_mux_enum_put,
4115 },
4116 {}
4117};
4118
4119static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004120 .build_controls = stac92xx_build_controls,
4121 .build_pcms = stac92xx_build_pcms,
4122 .init = stac92xx_init,
4123 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004124#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004125 .resume = stac92xx_resume,
4126#endif
4127};
4128
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004129static int stac9872_vaio_init(struct hda_codec *codec)
4130{
4131 int err;
4132
4133 err = stac92xx_init(codec);
4134 if (err < 0)
4135 return err;
4136 if (codec->patch_ops.unsol_event)
4137 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4138 return 0;
4139}
4140
4141static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4142{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004143 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004144 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4145 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4146 } else {
4147 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4148 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4149 }
4150}
4151
4152static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4153{
4154 switch (res >> 26) {
4155 case STAC_HP_EVENT:
4156 stac9872_vaio_hp_detect(codec, res);
4157 break;
4158 }
4159}
4160
4161static struct hda_codec_ops stac9872_vaio_patch_ops = {
4162 .build_controls = stac92xx_build_controls,
4163 .build_pcms = stac92xx_build_pcms,
4164 .init = stac9872_vaio_init,
4165 .free = stac92xx_free,
4166 .unsol_event = stac9872_vaio_unsol_event,
4167#ifdef CONFIG_PM
4168 .resume = stac92xx_resume,
4169#endif
4170};
4171
Guillaume Munch6d859062006-08-22 17:15:47 +02004172enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4173 CXD9872RD_VAIO,
4174 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4175 STAC9872AK_VAIO,
4176 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4177 STAC9872K_VAIO,
4178 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004179 CXD9872AKD_VAIO,
4180 STAC_9872_MODELS,
4181};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004182
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004183static const char *stac9872_models[STAC_9872_MODELS] = {
4184 [CXD9872RD_VAIO] = "vaio",
4185 [CXD9872AKD_VAIO] = "vaio-ar",
4186};
4187
4188static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4189 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4190 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4191 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004192 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004193 {}
4194};
4195
Guillaume Munch6d859062006-08-22 17:15:47 +02004196static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004197{
4198 struct sigmatel_spec *spec;
4199 int board_config;
4200
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004201 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4202 stac9872_models,
4203 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004204 if (board_config < 0)
4205 /* unknown config, let generic-parser do its job... */
4206 return snd_hda_parse_generic_codec(codec);
4207
4208 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4209 if (spec == NULL)
4210 return -ENOMEM;
4211
4212 codec->spec = spec;
4213 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004214 case CXD9872RD_VAIO:
4215 case STAC9872AK_VAIO:
4216 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004217 spec->mixer = vaio_mixer;
4218 spec->init = vaio_init;
4219 spec->multiout.max_channels = 2;
4220 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4221 spec->multiout.dac_nids = vaio_dacs;
4222 spec->multiout.hp_nid = VAIO_HP_DAC;
4223 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4224 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004225 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004226 spec->input_mux = &vaio_mux;
4227 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004228 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004229 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004230
4231 case CXD9872AKD_VAIO:
4232 spec->mixer = vaio_ar_mixer;
4233 spec->init = vaio_ar_init;
4234 spec->multiout.max_channels = 2;
4235 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4236 spec->multiout.dac_nids = vaio_dacs;
4237 spec->multiout.hp_nid = VAIO_HP_DAC;
4238 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004239 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004240 spec->adc_nids = vaio_adcs;
4241 spec->input_mux = &vaio_mux;
4242 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004243 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004244 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004245 }
4246
Takashi Iwaidb064e52006-03-16 16:04:58 +01004247 return 0;
4248}
4249
4250
4251/*
Matt2f2f4252005-04-13 14:45:30 +02004252 * patch entries
4253 */
4254struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4255 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4256 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4257 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4258 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4259 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4260 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4261 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004262 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4263 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4264 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4265 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4266 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4267 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004268 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4269 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4270 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4271 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4272 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4273 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4274 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4275 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4276 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4277 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004278 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4279 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4280 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4281 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4282 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4283 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02004284 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
4285 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004286 /* The following does not take into account .id=0x83847661 when subsys =
4287 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4288 * currently not fully supported.
4289 */
4290 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4291 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4292 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004293 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4294 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4295 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4296 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4297 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4298 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4299 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4300 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004301 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4302 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004303 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004304 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4305 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4306 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4307 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4308 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4309 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4310 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4311 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4312 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004313 {} /* terminator */
4314};