blob: 314ea51538b77ebb5684d57bd3e7b1f83acd3a66 [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
35
Matt4e550962005-07-04 17:51:39 +020036#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010037#define STAC_PWR_EVENT 0x20
38#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020039
Takashi Iwaif5fcc132006-11-24 17:07:44 +010040enum {
41 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010042 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020043 STAC_9200_DELL_D21,
44 STAC_9200_DELL_D22,
45 STAC_9200_DELL_D23,
46 STAC_9200_DELL_M21,
47 STAC_9200_DELL_M22,
48 STAC_9200_DELL_M23,
49 STAC_9200_DELL_M24,
50 STAC_9200_DELL_M25,
51 STAC_9200_DELL_M26,
52 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020053 STAC_9200_GATEWAY,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010054 STAC_9200_MODELS
55};
56
57enum {
58 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020059 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020060 STAC_9205_DELL_M43,
61 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010062 STAC_9205_MODELS
63};
64
65enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010066 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010067 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010068 STAC_92HD73XX_MODELS
69};
70
71enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010072 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010073 STAC_DELL_M4_1,
74 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010075 STAC_92HD71BXX_MODELS
76};
77
78enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010079 STAC_925x_REF,
80 STAC_M2_2,
81 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020082 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010083 STAC_925x_MODELS
84};
85
86enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010087 STAC_D945_REF,
88 STAC_D945GTP3,
89 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020090 STAC_INTEL_MAC_V1,
91 STAC_INTEL_MAC_V2,
92 STAC_INTEL_MAC_V3,
93 STAC_INTEL_MAC_V4,
94 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020095 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010096 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010097 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010098 STAC_MACBOOK_PRO_V1,
99 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200100 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200101 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200102 STAC_922X_DELL_D81,
103 STAC_922X_DELL_D82,
104 STAC_922X_DELL_M81,
105 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100106 STAC_922X_MODELS
107};
108
109enum {
110 STAC_D965_REF,
111 STAC_D965_3ST,
112 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200113 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100114 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100115 STAC_927X_MODELS
116};
Matt Porter403d1942005-11-29 15:00:51 +0100117
Matt2f2f4252005-04-13 14:45:30 +0200118struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100119 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200120 unsigned int num_mixers;
121
Matt Porter403d1942005-11-29 15:00:51 +0100122 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200123 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100124 unsigned int line_switch: 1;
125 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100126 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100127 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200128
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100129 /* gpio lines */
130 unsigned int gpio_mask;
131 unsigned int gpio_dir;
132 unsigned int gpio_data;
133 unsigned int gpio_mute;
134
135 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100136 unsigned char aloopback_mask;
137 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200138
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100139 /* power management */
140 unsigned int num_pwrs;
141 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100142 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100143
Matt2f2f4252005-04-13 14:45:30 +0200144 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100145 struct hda_input_mux *mono_mux;
146 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200147 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100148 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200149
150 /* capture */
151 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200152 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200153 hda_nid_t *mux_nids;
154 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200155 hda_nid_t *dmic_nids;
156 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100157 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100158 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200159 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100160 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200161
Matt2f2f4252005-04-13 14:45:30 +0200162 /* pin widgets */
163 hda_nid_t *pin_nids;
164 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200165 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200166 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200167
168 /* codec specific stuff */
169 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100170 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200171
172 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200173 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100174 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200175 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100176 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200177
Matt Porter403d1942005-11-29 15:00:51 +0100178 /* i/o switches */
179 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200180 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200181 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200182
Mattc7d4b2f2005-06-27 14:59:41 +0200183 struct hda_pcm pcm_rec[2]; /* PCM information */
184
185 /* dynamic controls and input_mux */
186 struct auto_pin_cfg autocfg;
187 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100188 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200189 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200190 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100191 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200192};
193
194static hda_nid_t stac9200_adc_nids[1] = {
195 0x03,
196};
197
198static hda_nid_t stac9200_mux_nids[1] = {
199 0x0c,
200};
201
202static hda_nid_t stac9200_dac_nids[1] = {
203 0x02,
204};
205
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100206static hda_nid_t stac92hd73xx_pwr_nids[8] = {
207 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
208 0x0f, 0x10, 0x11
209};
210
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100211static hda_nid_t stac92hd73xx_adc_nids[2] = {
212 0x1a, 0x1b
213};
214
215#define STAC92HD73XX_NUM_DMICS 2
216static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
217 0x13, 0x14, 0
218};
219
220#define STAC92HD73_DAC_COUNT 5
221static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
222 0x15, 0x16, 0x17, 0x18, 0x19,
223};
224
225static hda_nid_t stac92hd73xx_mux_nids[4] = {
226 0x28, 0x29, 0x2a, 0x2b,
227};
228
229static hda_nid_t stac92hd73xx_dmux_nids[2] = {
230 0x20, 0x21,
231};
232
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100233static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
234 0x0a, 0x0d, 0x0f
235};
236
Matthew Ranostaye035b842007-11-06 11:53:55 +0100237static hda_nid_t stac92hd71bxx_adc_nids[2] = {
238 0x12, 0x13,
239};
240
241static hda_nid_t stac92hd71bxx_mux_nids[2] = {
242 0x1a, 0x1b
243};
244
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100245static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
246 0x1c,
247};
248
Matthew Ranostaye035b842007-11-06 11:53:55 +0100249static hda_nid_t stac92hd71bxx_dac_nids[2] = {
250 0x10, /*0x11, */
251};
252
253#define STAC92HD71BXX_NUM_DMICS 2
254static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
255 0x18, 0x19, 0
256};
257
Tobin Davis8e21c342007-01-08 11:04:17 +0100258static hda_nid_t stac925x_adc_nids[1] = {
259 0x03,
260};
261
262static hda_nid_t stac925x_mux_nids[1] = {
263 0x0f,
264};
265
266static hda_nid_t stac925x_dac_nids[1] = {
267 0x02,
268};
269
Takashi Iwaif6e98522007-10-16 14:27:04 +0200270#define STAC925X_NUM_DMICS 1
271static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
272 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200273};
274
Takashi Iwai1697055e2007-12-18 18:05:52 +0100275static hda_nid_t stac925x_dmux_nids[1] = {
276 0x14,
277};
278
Matt2f2f4252005-04-13 14:45:30 +0200279static hda_nid_t stac922x_adc_nids[2] = {
280 0x06, 0x07,
281};
282
283static hda_nid_t stac922x_mux_nids[2] = {
284 0x12, 0x13,
285};
286
Matt Porter3cc08dc2006-01-23 15:27:49 +0100287static hda_nid_t stac927x_adc_nids[3] = {
288 0x07, 0x08, 0x09
289};
290
291static hda_nid_t stac927x_mux_nids[3] = {
292 0x15, 0x16, 0x17
293};
294
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100295static hda_nid_t stac927x_dac_nids[6] = {
296 0x02, 0x03, 0x04, 0x05, 0x06, 0
297};
298
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100299static hda_nid_t stac927x_dmux_nids[1] = {
300 0x1b,
301};
302
Matthew Ranostay7f168592007-10-18 17:38:17 +0200303#define STAC927X_NUM_DMICS 2
304static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
305 0x13, 0x14, 0
306};
307
Matt Porterf3302a52006-07-31 12:49:34 +0200308static hda_nid_t stac9205_adc_nids[2] = {
309 0x12, 0x13
310};
311
312static hda_nid_t stac9205_mux_nids[2] = {
313 0x19, 0x1a
314};
315
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100316static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100317 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100318};
319
Takashi Iwaif6e98522007-10-16 14:27:04 +0200320#define STAC9205_NUM_DMICS 2
321static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
322 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200323};
324
Mattc7d4b2f2005-06-27 14:59:41 +0200325static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200326 0x08, 0x09, 0x0d, 0x0e,
327 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200328};
329
Tobin Davis8e21c342007-01-08 11:04:17 +0100330static hda_nid_t stac925x_pin_nids[8] = {
331 0x07, 0x08, 0x0a, 0x0b,
332 0x0c, 0x0d, 0x10, 0x11,
333};
334
Matt2f2f4252005-04-13 14:45:30 +0200335static hda_nid_t stac922x_pin_nids[10] = {
336 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
337 0x0f, 0x10, 0x11, 0x15, 0x1b,
338};
339
Matthew Ranostaya7662642008-02-21 07:51:14 +0100340static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100341 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
342 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100343 0x14, 0x1e, 0x22
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100344};
345
Matthew Ranostaye035b842007-11-06 11:53:55 +0100346static hda_nid_t stac92hd71bxx_pin_nids[10] = {
347 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
348 0x0f, 0x14, 0x18, 0x19, 0x1e,
349};
350
Matt Porter3cc08dc2006-01-23 15:27:49 +0100351static hda_nid_t stac927x_pin_nids[14] = {
352 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
353 0x0f, 0x10, 0x11, 0x12, 0x13,
354 0x14, 0x21, 0x22, 0x23,
355};
356
Matt Porterf3302a52006-07-31 12:49:34 +0200357static hda_nid_t stac9205_pin_nids[12] = {
358 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
359 0x0f, 0x14, 0x16, 0x17, 0x18,
360 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200361};
362
Matt Porter8b657272006-10-26 17:12:59 +0200363static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
364 struct snd_ctl_elem_info *uinfo)
365{
366 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
367 struct sigmatel_spec *spec = codec->spec;
368 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
369}
370
371static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_value *ucontrol)
373{
374 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
375 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100376 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200377
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100378 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200379 return 0;
380}
381
382static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
383 struct snd_ctl_elem_value *ucontrol)
384{
385 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
386 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100387 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200388
389 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100390 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200391}
392
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100393static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200394{
395 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
396 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200397 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200398}
399
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100400static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200401{
402 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
403 struct sigmatel_spec *spec = codec->spec;
404 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
405
406 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
407 return 0;
408}
409
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100410static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200411{
412 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
413 struct sigmatel_spec *spec = codec->spec;
414 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
415
Mattc7d4b2f2005-06-27 14:59:41 +0200416 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200417 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
418}
419
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100420static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
421 struct snd_ctl_elem_info *uinfo)
422{
423 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
424 struct sigmatel_spec *spec = codec->spec;
425 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
426}
427
428static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
429 struct snd_ctl_elem_value *ucontrol)
430{
431 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
432 struct sigmatel_spec *spec = codec->spec;
433
434 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
435 return 0;
436}
437
438static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_value *ucontrol)
440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
442 struct sigmatel_spec *spec = codec->spec;
443
444 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
445 spec->mono_nid, &spec->cur_mmux);
446}
447
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200448#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
449
450static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
451 struct snd_ctl_elem_value *ucontrol)
452{
453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100454 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200455 struct sigmatel_spec *spec = codec->spec;
456
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100457 ucontrol->value.integer.value[0] = !!(spec->aloopback &
458 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200459 return 0;
460}
461
462static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_value *ucontrol)
464{
465 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
466 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100467 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200468 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100469 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200470
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100471 idx_val = spec->aloopback_mask << idx;
472 if (ucontrol->value.integer.value[0])
473 val = spec->aloopback | idx_val;
474 else
475 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100476 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200477 return 0;
478
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100479 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200480
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100481 /* Only return the bits defined by the shift value of the
482 * first two bytes of the mask
483 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200484 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100485 kcontrol->private_value & 0xFFFF, 0x0);
486 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200487
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100488 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200489 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100490 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200491 } else {
492 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100493 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200494 }
495
496 snd_hda_codec_write_cache(codec, codec->afg, 0,
497 kcontrol->private_value >> 16, dac_mode);
498
499 return 1;
500}
501
Mattc7d4b2f2005-06-27 14:59:41 +0200502static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200503 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200504 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200505 {}
506};
507
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200508static struct hda_verb stac9200_eapd_init[] = {
509 /* set dac0mux for dac converter */
510 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
511 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
512 {}
513};
514
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100515static struct hda_verb stac92hd73xx_6ch_core_init[] = {
516 /* set master volume and direct control */
517 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
518 /* setup audio connections */
519 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
520 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
521 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
522 /* setup adcs to point to mixer */
523 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
524 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100525 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
526 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
527 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
528 /* setup import muxs */
529 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
530 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
531 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
532 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
533 {}
534};
535
536static struct hda_verb stac92hd73xx_8ch_core_init[] = {
537 /* set master volume and direct control */
538 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
539 /* setup audio connections */
540 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
541 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
542 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
543 /* connect hp ports to dac3 */
544 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
545 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
546 /* setup adcs to point to mixer */
547 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
548 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100549 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
550 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
551 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
552 /* setup import muxs */
553 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
554 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
555 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
556 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
557 {}
558};
559
560static struct hda_verb stac92hd73xx_10ch_core_init[] = {
561 /* set master volume and direct control */
562 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
563 /* setup audio connections */
564 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
565 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
566 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
567 /* dac3 is connected to import3 mux */
568 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
569 /* connect hp ports to dac4 */
570 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
571 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
572 /* setup adcs to point to mixer */
573 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
574 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100575 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
576 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
577 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
578 /* setup import muxs */
579 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
580 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
581 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
582 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
583 {}
584};
585
Matthew Ranostaye035b842007-11-06 11:53:55 +0100586static struct hda_verb stac92hd71bxx_core_init[] = {
587 /* set master volume and direct control */
588 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
589 /* connect headphone jack to dac1 */
590 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100591 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
592 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
593 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
594 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
595 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100596};
597
598static struct hda_verb stac92hd71bxx_analog_core_init[] = {
599 /* set master volume and direct control */
600 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
601 /* connect headphone jack to dac1 */
602 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100603 /* connect ports 0d and 0f to audio mixer */
604 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
605 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100606 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100607 /* unmute dac0 input in audio mixer */
608 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100609 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
610 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
611 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
612 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100613 {}
614};
615
Tobin Davis8e21c342007-01-08 11:04:17 +0100616static struct hda_verb stac925x_core_init[] = {
617 /* set dac0mux for dac converter */
618 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
619 {}
620};
621
Mattc7d4b2f2005-06-27 14:59:41 +0200622static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200623 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200624 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200625 {}
626};
627
Tobin Davis93ed1502006-09-01 21:03:12 +0200628static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200629 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200630 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200631 /* unmute node 0x1b */
632 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
633 /* select node 0x03 as DAC */
634 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
635 {}
636};
637
Matt Porter3cc08dc2006-01-23 15:27:49 +0100638static struct hda_verb stac927x_core_init[] = {
639 /* set master volume and direct control */
640 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
641 {}
642};
643
Matt Porterf3302a52006-07-31 12:49:34 +0200644static struct hda_verb stac9205_core_init[] = {
645 /* set master volume and direct control */
646 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
647 {}
648};
649
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100650#define STAC_MONO_MUX \
651 { \
652 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
653 .name = "Mono Mux", \
654 .count = 1, \
655 .info = stac92xx_mono_mux_enum_info, \
656 .get = stac92xx_mono_mux_enum_get, \
657 .put = stac92xx_mono_mux_enum_put, \
658 }
659
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200660#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200661 { \
662 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
663 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200664 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200665 .info = stac92xx_mux_enum_info, \
666 .get = stac92xx_mux_enum_get, \
667 .put = stac92xx_mux_enum_put, \
668 }
669
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100670#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200671 { \
672 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
673 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100674 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200675 .info = stac92xx_aloopback_info, \
676 .get = stac92xx_aloopback_get, \
677 .put = stac92xx_aloopback_put, \
678 .private_value = verb_read | (verb_write << 16), \
679 }
680
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100681static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200682 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
683 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200684 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200685 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
686 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200687 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200688 { } /* end */
689};
690
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100691static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
693
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100694 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
695 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
696
697 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
698 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
699
700 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
701 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
702
703 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
704 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
705
706 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
707 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
708
709 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
710 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
711
712 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
713 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
714 { } /* end */
715};
716
717static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100718 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
719
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100720 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
721 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
722
723 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
724 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
725
726 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
727 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
728
729 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
730 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
731
732 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
733 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
734
735 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
736 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
737
738 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
739 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
740 { } /* end */
741};
742
743static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100744 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
745
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100746 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
747 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
748
749 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
750 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
751
752 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
753 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
754
755 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
756 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
757
758 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
759 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
760
761 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
762 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
763
764 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
765 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
766 { } /* end */
767};
768
Matthew Ranostay541eee82007-12-14 12:08:04 +0100769static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100770 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100771
Matthew Ranostay9b359472007-11-07 13:03:12 +0100772 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
773 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
774 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
775
776 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
777 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
778 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
779
780 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
781 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100782 { } /* end */
783};
784
Matthew Ranostay541eee82007-12-14 12:08:04 +0100785static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100786 STAC_INPUT_SOURCE(2),
787 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
788
Matthew Ranostay541eee82007-12-14 12:08:04 +0100789 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
790 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
791 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
792
793 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
794 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
795 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
796 { } /* end */
797};
798
Tobin Davis8e21c342007-01-08 11:04:17 +0100799static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200800 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100801 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
802 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
803 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
804 { } /* end */
805};
806
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100807static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200808 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100809 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200810
811 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
812 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
813 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
814
815 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
816 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
817 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
818
819 { } /* end */
820};
821
822/* This needs to be generated dynamically based on sequence */
823static struct snd_kcontrol_new stac922x_mixer[] = {
824 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200825 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
826 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
827 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
828
829 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
830 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
831 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
832 { } /* end */
833};
834
835
836static struct snd_kcontrol_new stac927x_mixer[] = {
837 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100838 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200839
840 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
841 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
842 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
843
844 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
845 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
846 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
847
848 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
849 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
850 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200851 { } /* end */
852};
853
Takashi Iwai1697055e2007-12-18 18:05:52 +0100854static struct snd_kcontrol_new stac_dmux_mixer = {
855 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
856 .name = "Digital Input Source",
857 /* count set later */
858 .info = stac92xx_dmux_enum_info,
859 .get = stac92xx_dmux_enum_get,
860 .put = stac92xx_dmux_enum_put,
861};
862
Takashi Iwai2134ea42008-01-10 16:53:55 +0100863static const char *slave_vols[] = {
864 "Front Playback Volume",
865 "Surround Playback Volume",
866 "Center Playback Volume",
867 "LFE Playback Volume",
868 "Side Playback Volume",
869 "Headphone Playback Volume",
870 "Headphone Playback Volume",
871 "Speaker Playback Volume",
872 "External Speaker Playback Volume",
873 "Speaker2 Playback Volume",
874 NULL
875};
876
877static const char *slave_sws[] = {
878 "Front Playback Switch",
879 "Surround Playback Switch",
880 "Center Playback Switch",
881 "LFE Playback Switch",
882 "Side Playback Switch",
883 "Headphone Playback Switch",
884 "Headphone Playback Switch",
885 "Speaker Playback Switch",
886 "External Speaker Playback Switch",
887 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100888 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100889 NULL
890};
891
Matt2f2f4252005-04-13 14:45:30 +0200892static int stac92xx_build_controls(struct hda_codec *codec)
893{
894 struct sigmatel_spec *spec = codec->spec;
895 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200896 int i;
Matt2f2f4252005-04-13 14:45:30 +0200897
898 err = snd_hda_add_new_ctls(codec, spec->mixer);
899 if (err < 0)
900 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200901
902 for (i = 0; i < spec->num_mixers; i++) {
903 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
904 if (err < 0)
905 return err;
906 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100907 if (spec->num_dmuxes > 0) {
908 stac_dmux_mixer.count = spec->num_dmuxes;
909 err = snd_ctl_add(codec->bus->card,
910 snd_ctl_new1(&stac_dmux_mixer, codec));
911 if (err < 0)
912 return err;
913 }
Mattc7d4b2f2005-06-27 14:59:41 +0200914
Mattdabbed62005-06-14 10:19:34 +0200915 if (spec->multiout.dig_out_nid) {
916 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
917 if (err < 0)
918 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100919 err = snd_hda_create_spdif_share_sw(codec,
920 &spec->multiout);
921 if (err < 0)
922 return err;
923 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200924 }
925 if (spec->dig_in_nid) {
926 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
927 if (err < 0)
928 return err;
929 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100930
931 /* if we have no master control, let's create it */
932 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100933 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100934 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100935 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100936 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100937 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100938 if (err < 0)
939 return err;
940 }
941 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
942 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
943 NULL, slave_sws);
944 if (err < 0)
945 return err;
946 }
947
Mattdabbed62005-06-14 10:19:34 +0200948 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200949}
950
Matt Porter403d1942005-11-29 15:00:51 +0100951static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200952 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200953 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
954};
955
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200956/*
957 STAC 9200 pin configs for
958 102801A8
959 102801DE
960 102801E8
961*/
962static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200963 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
964 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200965};
966
967/*
968 STAC 9200 pin configs for
969 102801C0
970 102801C1
971*/
972static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200973 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
974 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200975};
976
977/*
978 STAC 9200 pin configs for
979 102801C4 (Dell Dimension E310)
980 102801C5
981 102801C7
982 102801D9
983 102801DA
984 102801E3
985*/
986static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200987 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
988 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200989};
990
991
992/*
993 STAC 9200-32 pin configs for
994 102801B5 (Dell Inspiron 630m)
995 102801D8 (Dell Inspiron 640m)
996*/
997static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200998 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
999 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001000};
1001
1002/*
1003 STAC 9200-32 pin configs for
1004 102801C2 (Dell Latitude D620)
1005 102801C8
1006 102801CC (Dell Latitude D820)
1007 102801D4
1008 102801D6
1009*/
1010static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001011 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1012 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001013};
1014
1015/*
1016 STAC 9200-32 pin configs for
1017 102801CE (Dell XPS M1710)
1018 102801CF (Dell Precision M90)
1019*/
1020static unsigned int dell9200_m23_pin_configs[8] = {
1021 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1022 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1023};
1024
1025/*
1026 STAC 9200-32 pin configs for
1027 102801C9
1028 102801CA
1029 102801CB (Dell Latitude 120L)
1030 102801D3
1031*/
1032static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001033 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1034 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001035};
1036
1037/*
1038 STAC 9200-32 pin configs for
1039 102801BD (Dell Inspiron E1505n)
1040 102801EE
1041 102801EF
1042*/
1043static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001044 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1045 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001046};
1047
1048/*
1049 STAC 9200-32 pin configs for
1050 102801F5 (Dell Inspiron 1501)
1051 102801F6
1052*/
1053static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001054 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1055 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001056};
1057
1058/*
1059 STAC 9200-32
1060 102801CD (Dell Inspiron E1705/9400)
1061*/
1062static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001063 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1064 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001065};
1066
Tobin Davisbf277782008-02-03 20:31:47 +01001067static unsigned int oqo9200_pin_configs[8] = {
1068 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1069 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1070};
1071
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001072
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001073static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1074 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001075 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001076 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1077 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1078 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1079 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1080 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1081 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1082 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1083 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1084 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1085 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001086};
1087
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001088static const char *stac9200_models[STAC_9200_MODELS] = {
1089 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001090 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001091 [STAC_9200_DELL_D21] = "dell-d21",
1092 [STAC_9200_DELL_D22] = "dell-d22",
1093 [STAC_9200_DELL_D23] = "dell-d23",
1094 [STAC_9200_DELL_M21] = "dell-m21",
1095 [STAC_9200_DELL_M22] = "dell-m22",
1096 [STAC_9200_DELL_M23] = "dell-m23",
1097 [STAC_9200_DELL_M24] = "dell-m24",
1098 [STAC_9200_DELL_M25] = "dell-m25",
1099 [STAC_9200_DELL_M26] = "dell-m26",
1100 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001101 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001102};
1103
1104static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1105 /* SigmaTel reference board */
1106 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1107 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001108 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001109 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1110 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001111 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001112 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1113 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1114 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1115 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1116 "unknown Dell", STAC_9200_DELL_D22),
1117 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1118 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001119 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001120 "Dell Latitude D620", STAC_9200_DELL_M22),
1121 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1122 "unknown Dell", STAC_9200_DELL_D23),
1123 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1124 "unknown Dell", STAC_9200_DELL_D23),
1125 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1126 "unknown Dell", STAC_9200_DELL_M22),
1127 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1128 "unknown Dell", STAC_9200_DELL_M24),
1129 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1130 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001131 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001132 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001133 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001134 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001135 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001136 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001137 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001138 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001139 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001140 "Dell Precision M90", STAC_9200_DELL_M23),
1141 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1142 "unknown Dell", STAC_9200_DELL_M22),
1143 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1144 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001145 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001146 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001147 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001148 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1149 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1150 "unknown Dell", STAC_9200_DELL_D23),
1151 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1152 "unknown Dell", STAC_9200_DELL_D23),
1153 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1154 "unknown Dell", STAC_9200_DELL_D21),
1155 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1156 "unknown Dell", STAC_9200_DELL_D23),
1157 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1158 "unknown Dell", STAC_9200_DELL_D21),
1159 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1160 "unknown Dell", STAC_9200_DELL_M25),
1161 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1162 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001163 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001164 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1165 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1166 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001167 /* Panasonic */
1168 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001169 /* Gateway machines needs EAPD to be set on resume */
1170 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1171 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1172 STAC_9200_GATEWAY),
1173 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1174 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001175 /* OQO Mobile */
1176 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001177 {} /* terminator */
1178};
1179
Tobin Davis8e21c342007-01-08 11:04:17 +01001180static unsigned int ref925x_pin_configs[8] = {
1181 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001182 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001183};
1184
1185static unsigned int stac925x_MA6_pin_configs[8] = {
1186 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1187 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1188};
1189
Tobin Davis2c11f952007-05-17 09:36:34 +02001190static unsigned int stac925x_PA6_pin_configs[8] = {
1191 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1192 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1193};
1194
Tobin Davis8e21c342007-01-08 11:04:17 +01001195static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001196 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1197 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001198};
1199
1200static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1201 [STAC_REF] = ref925x_pin_configs,
1202 [STAC_M2_2] = stac925xM2_2_pin_configs,
1203 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001204 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001205};
1206
1207static const char *stac925x_models[STAC_925x_MODELS] = {
1208 [STAC_REF] = "ref",
1209 [STAC_M2_2] = "m2-2",
1210 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001211 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001212};
1213
1214static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1215 /* SigmaTel reference board */
1216 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001217 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001218 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1219 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1220 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001221 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001222 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1223 {} /* terminator */
1224};
1225
Matthew Ranostaya7662642008-02-21 07:51:14 +01001226static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001227 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1228 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1229 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001230 0x01452050,
1231};
1232
1233static unsigned int dell_m6_pin_configs[13] = {
1234 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
1235 0x03a11020, 0x03011050, 0x4f0000f0, 0x4f0000f0,
1236 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1237 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001238};
1239
1240static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001241 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1242 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001243};
1244
1245static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1246 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001247 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001248};
1249
1250static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1251 /* SigmaTel reference board */
1252 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001253 "DFI LanParty", STAC_92HD73XX_REF),
1254 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1255 "unknown Dell", STAC_DELL_M6),
1256 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1257 "unknown Dell", STAC_DELL_M6),
1258 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1259 "unknown Dell", STAC_DELL_M6),
1260 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1261 "unknown Dell", STAC_DELL_M6),
1262 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1263 "unknown Dell", STAC_DELL_M6),
1264 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1265 "unknown Dell", STAC_DELL_M6),
1266 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1267 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001268 {} /* terminator */
1269};
1270
Matthew Ranostaye035b842007-11-06 11:53:55 +01001271static unsigned int ref92hd71bxx_pin_configs[10] = {
1272 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001273 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001274 0x90a000f0, 0x01452050,
1275};
1276
Matthew Ranostaya7662642008-02-21 07:51:14 +01001277static unsigned int dell_m4_1_pin_configs[13] = {
1278 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
1279 0x23a1902e, 0x23014250, 0x40f000f0, 0x4f0000f0,
1280 0x40f000f0, 0x4f0000f0,
1281};
1282
1283static unsigned int dell_m4_2_pin_configs[13] = {
1284 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1285 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1286 0x40f000f0, 0x044413b0,
1287};
1288
Matthew Ranostaye035b842007-11-06 11:53:55 +01001289static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1290 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001291 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1292 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001293};
1294
1295static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1296 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001297 [STAC_DELL_M4_1] = "dell-m4-1",
1298 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001299};
1300
1301static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1302 /* SigmaTel reference board */
1303 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1304 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001305 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1306 "unknown Dell", STAC_DELL_M4_1),
1307 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1308 "unknown Dell", STAC_DELL_M4_1),
1309 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1310 "unknown Dell", STAC_DELL_M4_1),
1311 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1312 "unknown Dell", STAC_DELL_M4_1),
1313 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1314 "unknown Dell", STAC_DELL_M4_1),
1315 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1316 "unknown Dell", STAC_DELL_M4_1),
1317 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1318 "unknown Dell", STAC_DELL_M4_1),
1319 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1320 "unknown Dell", STAC_DELL_M4_2),
1321 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1322 "unknown Dell", STAC_DELL_M4_2),
1323 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1324 "unknown Dell", STAC_DELL_M4_2),
1325 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1326 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001327 {} /* terminator */
1328};
1329
Matt Porter403d1942005-11-29 15:00:51 +01001330static unsigned int ref922x_pin_configs[10] = {
1331 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1332 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001333 0x40000100, 0x40000100,
1334};
1335
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001336/*
1337 STAC 922X pin configs for
1338 102801A7
1339 102801AB
1340 102801A9
1341 102801D1
1342 102801D2
1343*/
1344static unsigned int dell_922x_d81_pin_configs[10] = {
1345 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1346 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1347 0x01813122, 0x400001f2,
1348};
1349
1350/*
1351 STAC 922X pin configs for
1352 102801AC
1353 102801D0
1354*/
1355static unsigned int dell_922x_d82_pin_configs[10] = {
1356 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1357 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1358 0x01813122, 0x400001f1,
1359};
1360
1361/*
1362 STAC 922X pin configs for
1363 102801BF
1364*/
1365static unsigned int dell_922x_m81_pin_configs[10] = {
1366 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1367 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1368 0x40C003f1, 0x405003f0,
1369};
1370
1371/*
1372 STAC 9221 A1 pin configs for
1373 102801D7 (Dell XPS M1210)
1374*/
1375static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001376 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1377 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001378 0x508003f3, 0x405003f4,
1379};
1380
Matt Porter403d1942005-11-29 15:00:51 +01001381static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001382 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001383 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1384 0x02a19120, 0x40000100,
1385};
1386
1387static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001388 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1389 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001390 0x02a19320, 0x40000100,
1391};
1392
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001393static unsigned int intel_mac_v1_pin_configs[10] = {
1394 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1395 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001396 0x400000fc, 0x400000fb,
1397};
1398
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001399static unsigned int intel_mac_v2_pin_configs[10] = {
1400 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1401 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001402 0x400000fc, 0x400000fb,
1403};
1404
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001405static unsigned int intel_mac_v3_pin_configs[10] = {
1406 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1407 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1408 0x400000fc, 0x400000fb,
1409};
1410
1411static unsigned int intel_mac_v4_pin_configs[10] = {
1412 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1413 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1414 0x400000fc, 0x400000fb,
1415};
1416
1417static unsigned int intel_mac_v5_pin_configs[10] = {
1418 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1419 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1420 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001421};
1422
Takashi Iwai76c08822007-06-19 12:17:42 +02001423
Takashi Iwai19039bd2006-06-28 15:52:16 +02001424static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001425 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001426 [STAC_D945GTP3] = d945gtp3_pin_configs,
1427 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001428 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1429 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1430 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1431 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1432 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001433 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001434 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1435 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1436 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1437 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1438 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1439 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001440 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1441 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1442 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1443 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001444};
1445
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001446static const char *stac922x_models[STAC_922X_MODELS] = {
1447 [STAC_D945_REF] = "ref",
1448 [STAC_D945GTP5] = "5stack",
1449 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001450 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1451 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1452 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1453 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1454 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001455 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001456 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001457 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001458 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1459 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001460 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001461 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001462 [STAC_922X_DELL_D81] = "dell-d81",
1463 [STAC_922X_DELL_D82] = "dell-d82",
1464 [STAC_922X_DELL_M81] = "dell-m81",
1465 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001466};
1467
1468static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1469 /* SigmaTel reference board */
1470 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1471 "DFI LanParty", STAC_D945_REF),
1472 /* Intel 945G based systems */
1473 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1474 "Intel D945G", STAC_D945GTP3),
1475 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1476 "Intel D945G", STAC_D945GTP3),
1477 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1478 "Intel D945G", STAC_D945GTP3),
1479 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1480 "Intel D945G", STAC_D945GTP3),
1481 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1482 "Intel D945G", STAC_D945GTP3),
1483 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1484 "Intel D945G", STAC_D945GTP3),
1485 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1486 "Intel D945G", STAC_D945GTP3),
1487 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1488 "Intel D945G", STAC_D945GTP3),
1489 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1490 "Intel D945G", STAC_D945GTP3),
1491 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1492 "Intel D945G", STAC_D945GTP3),
1493 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1494 "Intel D945G", STAC_D945GTP3),
1495 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1496 "Intel D945G", STAC_D945GTP3),
1497 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1498 "Intel D945G", STAC_D945GTP3),
1499 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1500 "Intel D945G", STAC_D945GTP3),
1501 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1502 "Intel D945G", STAC_D945GTP3),
1503 /* Intel D945G 5-stack systems */
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1505 "Intel D945G", STAC_D945GTP5),
1506 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1507 "Intel D945G", STAC_D945GTP5),
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1509 "Intel D945G", STAC_D945GTP5),
1510 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1511 "Intel D945G", STAC_D945GTP5),
1512 /* Intel 945P based systems */
1513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1514 "Intel D945P", STAC_D945GTP3),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1516 "Intel D945P", STAC_D945GTP3),
1517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1518 "Intel D945P", STAC_D945GTP3),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1520 "Intel D945P", STAC_D945GTP3),
1521 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1522 "Intel D945P", STAC_D945GTP3),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1524 "Intel D945P", STAC_D945GTP5),
1525 /* other systems */
1526 /* Apple Mac Mini (early 2006) */
1527 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001528 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001529 /* Dell systems */
1530 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1531 "unknown Dell", STAC_922X_DELL_D81),
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1533 "unknown Dell", STAC_922X_DELL_D81),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1535 "unknown Dell", STAC_922X_DELL_D81),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1537 "unknown Dell", STAC_922X_DELL_D82),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1539 "unknown Dell", STAC_922X_DELL_M81),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1541 "unknown Dell", STAC_922X_DELL_D82),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1543 "unknown Dell", STAC_922X_DELL_D81),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1545 "unknown Dell", STAC_922X_DELL_D81),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1547 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001548 {} /* terminator */
1549};
1550
Matt Porter3cc08dc2006-01-23 15:27:49 +01001551static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001552 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1553 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1554 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1555 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001556};
1557
Tobin Davis93ed1502006-09-01 21:03:12 +02001558static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001559 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1560 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1561 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1562 0x40000100, 0x40000100
1563};
1564
Tobin Davis93ed1502006-09-01 21:03:12 +02001565static unsigned int d965_5st_pin_configs[14] = {
1566 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1567 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1568 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1569 0x40000100, 0x40000100
1570};
1571
Tobin Davis4ff076e2007-08-07 11:48:12 +02001572static unsigned int dell_3st_pin_configs[14] = {
1573 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1574 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001575 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001576 0x40c003fc, 0x40000100
1577};
1578
Tobin Davis93ed1502006-09-01 21:03:12 +02001579static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001580 [STAC_D965_REF] = ref927x_pin_configs,
1581 [STAC_D965_3ST] = d965_3st_pin_configs,
1582 [STAC_D965_5ST] = d965_5st_pin_configs,
1583 [STAC_DELL_3ST] = dell_3st_pin_configs,
1584 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001585};
1586
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001587static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001588 [STAC_D965_REF] = "ref",
1589 [STAC_D965_3ST] = "3stack",
1590 [STAC_D965_5ST] = "5stack",
1591 [STAC_DELL_3ST] = "dell-3stack",
1592 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001593};
1594
1595static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1596 /* SigmaTel reference board */
1597 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1598 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001599 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001600 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1601 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001602 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001603 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1604 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1605 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1606 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1607 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1608 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1609 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1610 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1611 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1612 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1613 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1614 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1615 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1616 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1617 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1618 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001619 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001620 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001621 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001622 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1623 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001624 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001625 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1626 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001627 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1628 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1629 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1630 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1631 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1632 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001633 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001634 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1635 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1636 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1637 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1638 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1639 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1640 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1641 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001643 {} /* terminator */
1644};
1645
Matt Porterf3302a52006-07-31 12:49:34 +02001646static unsigned int ref9205_pin_configs[12] = {
1647 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001648 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001649 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001650};
1651
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001652/*
1653 STAC 9205 pin configs for
1654 102801F1
1655 102801F2
1656 102801FC
1657 102801FD
1658 10280204
1659 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001660 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001661*/
1662static unsigned int dell_9205_m42_pin_configs[12] = {
1663 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1664 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1665 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1666};
1667
1668/*
1669 STAC 9205 pin configs for
1670 102801F9
1671 102801FA
1672 102801FE
1673 102801FF (Dell Precision M4300)
1674 10280206
1675 10280200
1676 10280201
1677*/
1678static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001679 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1680 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1681 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1682};
1683
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001684static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001685 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1686 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1687 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1688};
1689
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001690static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001691 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001692 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1693 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1694 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001695};
1696
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001697static const char *stac9205_models[STAC_9205_MODELS] = {
1698 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001699 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001700 [STAC_9205_DELL_M43] = "dell-m43",
1701 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001702};
1703
1704static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1705 /* SigmaTel reference board */
1706 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1707 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001708 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1709 "unknown Dell", STAC_9205_DELL_M42),
1710 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1711 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001712 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001713 "Dell Precision", STAC_9205_DELL_M43),
1714 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1715 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001716 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1717 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001718 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1719 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001720 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1721 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001722 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1723 "unknown Dell", STAC_9205_DELL_M42),
1724 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1725 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001726 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1727 "Dell Precision", STAC_9205_DELL_M43),
1728 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001729 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001730 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1731 "Dell Precision", STAC_9205_DELL_M43),
1732 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1733 "Dell Inspiron", STAC_9205_DELL_M44),
1734 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1735 "Dell Inspiron", STAC_9205_DELL_M44),
1736 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1737 "Dell Inspiron", STAC_9205_DELL_M44),
1738 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1739 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001740 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1741 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001742 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1743 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001744 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1745 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001746 {} /* terminator */
1747};
1748
Richard Fish11b44bb2006-08-23 18:31:34 +02001749static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1750{
1751 int i;
1752 struct sigmatel_spec *spec = codec->spec;
1753
1754 if (! spec->bios_pin_configs) {
1755 spec->bios_pin_configs = kcalloc(spec->num_pins,
1756 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1757 if (! spec->bios_pin_configs)
1758 return -ENOMEM;
1759 }
1760
1761 for (i = 0; i < spec->num_pins; i++) {
1762 hda_nid_t nid = spec->pin_nids[i];
1763 unsigned int pin_cfg;
1764
1765 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1766 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1767 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1768 nid, pin_cfg);
1769 spec->bios_pin_configs[i] = pin_cfg;
1770 }
1771
1772 return 0;
1773}
1774
Matthew Ranostay87d48362007-07-17 11:52:24 +02001775static void stac92xx_set_config_reg(struct hda_codec *codec,
1776 hda_nid_t pin_nid, unsigned int pin_config)
1777{
1778 int i;
1779 snd_hda_codec_write(codec, pin_nid, 0,
1780 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1781 pin_config & 0x000000ff);
1782 snd_hda_codec_write(codec, pin_nid, 0,
1783 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1784 (pin_config & 0x0000ff00) >> 8);
1785 snd_hda_codec_write(codec, pin_nid, 0,
1786 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1787 (pin_config & 0x00ff0000) >> 16);
1788 snd_hda_codec_write(codec, pin_nid, 0,
1789 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1790 pin_config >> 24);
1791 i = snd_hda_codec_read(codec, pin_nid, 0,
1792 AC_VERB_GET_CONFIG_DEFAULT,
1793 0x00);
1794 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1795 pin_nid, i);
1796}
1797
Matt2f2f4252005-04-13 14:45:30 +02001798static void stac92xx_set_config_regs(struct hda_codec *codec)
1799{
1800 int i;
1801 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001802
Matthew Ranostay87d48362007-07-17 11:52:24 +02001803 if (!spec->pin_configs)
1804 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001805
Matthew Ranostay87d48362007-07-17 11:52:24 +02001806 for (i = 0; i < spec->num_pins; i++)
1807 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1808 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001809}
Matt2f2f4252005-04-13 14:45:30 +02001810
Matt2f2f4252005-04-13 14:45:30 +02001811/*
1812 * Analog playback callbacks
1813 */
1814static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1815 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001816 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001817{
1818 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001819 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1820 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001821}
1822
1823static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1824 struct hda_codec *codec,
1825 unsigned int stream_tag,
1826 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001827 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001828{
1829 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001830 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001831}
1832
1833static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1834 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001835 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001836{
1837 struct sigmatel_spec *spec = codec->spec;
1838 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1839}
1840
1841/*
Mattdabbed62005-06-14 10:19:34 +02001842 * Digital playback callbacks
1843 */
1844static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1845 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001846 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001847{
1848 struct sigmatel_spec *spec = codec->spec;
1849 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1850}
1851
1852static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1853 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001854 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001855{
1856 struct sigmatel_spec *spec = codec->spec;
1857 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1858}
1859
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001860static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1861 struct hda_codec *codec,
1862 unsigned int stream_tag,
1863 unsigned int format,
1864 struct snd_pcm_substream *substream)
1865{
1866 struct sigmatel_spec *spec = codec->spec;
1867 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1868 stream_tag, format, substream);
1869}
1870
Mattdabbed62005-06-14 10:19:34 +02001871
1872/*
Matt2f2f4252005-04-13 14:45:30 +02001873 * Analog capture callbacks
1874 */
1875static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1876 struct hda_codec *codec,
1877 unsigned int stream_tag,
1878 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001879 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001880{
1881 struct sigmatel_spec *spec = codec->spec;
1882
1883 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1884 stream_tag, 0, format);
1885 return 0;
1886}
1887
1888static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1889 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001890 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001891{
1892 struct sigmatel_spec *spec = codec->spec;
1893
1894 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1895 return 0;
1896}
1897
Mattdabbed62005-06-14 10:19:34 +02001898static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1899 .substreams = 1,
1900 .channels_min = 2,
1901 .channels_max = 2,
1902 /* NID is set in stac92xx_build_pcms */
1903 .ops = {
1904 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001905 .close = stac92xx_dig_playback_pcm_close,
1906 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001907 },
1908};
1909
1910static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1911 .substreams = 1,
1912 .channels_min = 2,
1913 .channels_max = 2,
1914 /* NID is set in stac92xx_build_pcms */
1915};
1916
Matt2f2f4252005-04-13 14:45:30 +02001917static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1918 .substreams = 1,
1919 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001920 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001921 .nid = 0x02, /* NID to query formats and rates */
1922 .ops = {
1923 .open = stac92xx_playback_pcm_open,
1924 .prepare = stac92xx_playback_pcm_prepare,
1925 .cleanup = stac92xx_playback_pcm_cleanup
1926 },
1927};
1928
Matt Porter3cc08dc2006-01-23 15:27:49 +01001929static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1930 .substreams = 1,
1931 .channels_min = 2,
1932 .channels_max = 2,
1933 .nid = 0x06, /* NID to query formats and rates */
1934 .ops = {
1935 .open = stac92xx_playback_pcm_open,
1936 .prepare = stac92xx_playback_pcm_prepare,
1937 .cleanup = stac92xx_playback_pcm_cleanup
1938 },
1939};
1940
Matt2f2f4252005-04-13 14:45:30 +02001941static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001942 .channels_min = 2,
1943 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001944 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001945 .ops = {
1946 .prepare = stac92xx_capture_pcm_prepare,
1947 .cleanup = stac92xx_capture_pcm_cleanup
1948 },
1949};
1950
1951static int stac92xx_build_pcms(struct hda_codec *codec)
1952{
1953 struct sigmatel_spec *spec = codec->spec;
1954 struct hda_pcm *info = spec->pcm_rec;
1955
1956 codec->num_pcms = 1;
1957 codec->pcm_info = info;
1958
Mattc7d4b2f2005-06-27 14:59:41 +02001959 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001960 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001961 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001962 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001963 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001964
1965 if (spec->alt_switch) {
1966 codec->num_pcms++;
1967 info++;
1968 info->name = "STAC92xx Analog Alt";
1969 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1970 }
Matt2f2f4252005-04-13 14:45:30 +02001971
Mattdabbed62005-06-14 10:19:34 +02001972 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1973 codec->num_pcms++;
1974 info++;
1975 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001976 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02001977 if (spec->multiout.dig_out_nid) {
1978 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1979 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1980 }
1981 if (spec->dig_in_nid) {
1982 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1983 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1984 }
1985 }
1986
Matt2f2f4252005-04-13 14:45:30 +02001987 return 0;
1988}
1989
Takashi Iwaic960a032006-03-23 17:06:28 +01001990static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1991{
1992 unsigned int pincap = snd_hda_param_read(codec, nid,
1993 AC_PAR_PIN_CAP);
1994 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1995 if (pincap & AC_PINCAP_VREF_100)
1996 return AC_PINCTL_VREF_100;
1997 if (pincap & AC_PINCAP_VREF_80)
1998 return AC_PINCTL_VREF_80;
1999 if (pincap & AC_PINCAP_VREF_50)
2000 return AC_PINCTL_VREF_50;
2001 if (pincap & AC_PINCAP_VREF_GRD)
2002 return AC_PINCTL_VREF_GRD;
2003 return 0;
2004}
2005
Matt Porter403d1942005-11-29 15:00:51 +01002006static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2007
2008{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002009 snd_hda_codec_write_cache(codec, nid, 0,
2010 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002011}
2012
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002013#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002014
2015static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2016{
2017 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2018 struct sigmatel_spec *spec = codec->spec;
2019 int io_idx = kcontrol-> private_value & 0xff;
2020
2021 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2022 return 0;
2023}
2024
2025static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2026{
2027 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2028 struct sigmatel_spec *spec = codec->spec;
2029 hda_nid_t nid = kcontrol->private_value >> 8;
2030 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002031 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002032
2033 spec->io_switch[io_idx] = val;
2034
2035 if (val)
2036 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002037 else {
2038 unsigned int pinctl = AC_PINCTL_IN_EN;
2039 if (io_idx) /* set VREF for mic */
2040 pinctl |= stac92xx_get_vref(codec, nid);
2041 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2042 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002043
2044 /* check the auto-mute again: we need to mute/unmute the speaker
2045 * appropriately according to the pin direction
2046 */
2047 if (spec->hp_detect)
2048 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2049
Matt Porter403d1942005-11-29 15:00:51 +01002050 return 1;
2051}
2052
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002053#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2054
2055static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2056 struct snd_ctl_elem_value *ucontrol)
2057{
2058 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2059 struct sigmatel_spec *spec = codec->spec;
2060
2061 ucontrol->value.integer.value[0] = spec->clfe_swap;
2062 return 0;
2063}
2064
2065static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2066 struct snd_ctl_elem_value *ucontrol)
2067{
2068 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2069 struct sigmatel_spec *spec = codec->spec;
2070 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002071 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002072
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002073 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002074 return 0;
2075
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002076 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002077
2078 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2079 spec->clfe_swap ? 0x4 : 0x0);
2080
2081 return 1;
2082}
2083
Matt Porter403d1942005-11-29 15:00:51 +01002084#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2085 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2086 .name = xname, \
2087 .index = 0, \
2088 .info = stac92xx_io_switch_info, \
2089 .get = stac92xx_io_switch_get, \
2090 .put = stac92xx_io_switch_put, \
2091 .private_value = xpval, \
2092 }
2093
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002094#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2095 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2096 .name = xname, \
2097 .index = 0, \
2098 .info = stac92xx_clfe_switch_info, \
2099 .get = stac92xx_clfe_switch_get, \
2100 .put = stac92xx_clfe_switch_put, \
2101 .private_value = xpval, \
2102 }
Matt Porter403d1942005-11-29 15:00:51 +01002103
Mattc7d4b2f2005-06-27 14:59:41 +02002104enum {
2105 STAC_CTL_WIDGET_VOL,
2106 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002107 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002108 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002109 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002110};
2111
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002112static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002113 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2114 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002115 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002116 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002117 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002118};
2119
2120/* add dynamic controls */
2121static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2122{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002123 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002124
2125 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2126 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2127
2128 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2129 if (! knew)
2130 return -ENOMEM;
2131 if (spec->kctl_alloc) {
2132 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2133 kfree(spec->kctl_alloc);
2134 }
2135 spec->kctl_alloc = knew;
2136 spec->num_kctl_alloc = num;
2137 }
2138
2139 knew = &spec->kctl_alloc[spec->num_kctl_used];
2140 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002141 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002142 if (! knew->name)
2143 return -ENOMEM;
2144 knew->private_value = val;
2145 spec->num_kctl_used++;
2146 return 0;
2147}
2148
Matt Porter403d1942005-11-29 15:00:51 +01002149/* flag inputs as additional dynamic lineouts */
2150static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2151{
2152 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002153 unsigned int wcaps, wtype;
2154 int i, num_dacs = 0;
2155
2156 /* use the wcaps cache to count all DACs available for line-outs */
2157 for (i = 0; i < codec->num_nodes; i++) {
2158 wcaps = codec->wcaps[i];
2159 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002160
Steve Longerbeam7b043892007-05-03 20:50:03 +02002161 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2162 num_dacs++;
2163 }
Matt Porter403d1942005-11-29 15:00:51 +01002164
Steve Longerbeam7b043892007-05-03 20:50:03 +02002165 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2166
Matt Porter403d1942005-11-29 15:00:51 +01002167 switch (cfg->line_outs) {
2168 case 3:
2169 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002170 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002171 cfg->line_out_pins[cfg->line_outs] =
2172 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002173 spec->line_switch = 1;
2174 cfg->line_outs++;
2175 }
2176 break;
2177 case 2:
2178 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002179 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002180 cfg->line_out_pins[cfg->line_outs] =
2181 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002182 spec->line_switch = 1;
2183 cfg->line_outs++;
2184 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002185 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002186 cfg->line_out_pins[cfg->line_outs] =
2187 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002188 spec->mic_switch = 1;
2189 cfg->line_outs++;
2190 }
2191 break;
2192 case 1:
2193 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002194 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002195 cfg->line_out_pins[cfg->line_outs] =
2196 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002197 spec->line_switch = 1;
2198 cfg->line_outs++;
2199 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002200 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002201 cfg->line_out_pins[cfg->line_outs] =
2202 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002203 spec->mic_switch = 1;
2204 cfg->line_outs++;
2205 }
2206 break;
2207 }
2208
2209 return 0;
2210}
2211
Steve Longerbeam7b043892007-05-03 20:50:03 +02002212
2213static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2214{
2215 int i;
2216
2217 for (i = 0; i < spec->multiout.num_dacs; i++) {
2218 if (spec->multiout.dac_nids[i] == nid)
2219 return 1;
2220 }
2221
2222 return 0;
2223}
2224
Matt Porter3cc08dc2006-01-23 15:27:49 +01002225/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002226 * Fill in the dac_nids table from the parsed pin configuration
2227 * This function only works when every pin in line_out_pins[]
2228 * contains atleast one DAC in its connection list. Some 92xx
2229 * codecs are not connected directly to a DAC, such as the 9200
2230 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002231 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002232static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002233 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002234{
2235 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002236 int i, j, conn_len = 0;
2237 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2238 unsigned int wcaps, wtype;
2239
Mattc7d4b2f2005-06-27 14:59:41 +02002240 for (i = 0; i < cfg->line_outs; i++) {
2241 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002242 conn_len = snd_hda_get_connections(codec, nid, conn,
2243 HDA_MAX_CONNECTIONS);
2244 for (j = 0; j < conn_len; j++) {
2245 wcaps = snd_hda_param_read(codec, conn[j],
2246 AC_PAR_AUDIO_WIDGET_CAP);
2247 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002248 if (wtype != AC_WID_AUD_OUT ||
2249 (wcaps & AC_WCAP_DIGITAL))
2250 continue;
2251 /* conn[j] is a DAC routed to this line-out */
2252 if (!is_in_dac_nids(spec, conn[j]))
2253 break;
2254 }
2255
2256 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002257 if (spec->multiout.num_dacs > 0) {
2258 /* we have already working output pins,
2259 * so let's drop the broken ones again
2260 */
2261 cfg->line_outs = spec->multiout.num_dacs;
2262 break;
2263 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002264 /* error out, no available DAC found */
2265 snd_printk(KERN_ERR
2266 "%s: No available DAC for pin 0x%x\n",
2267 __func__, nid);
2268 return -ENODEV;
2269 }
2270
2271 spec->multiout.dac_nids[i] = conn[j];
2272 spec->multiout.num_dacs++;
2273 if (conn_len > 1) {
2274 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002275 snd_hda_codec_write_cache(codec, nid, 0,
2276 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002277
2278 }
Mattc7d4b2f2005-06-27 14:59:41 +02002279 }
2280
Steve Longerbeam7b043892007-05-03 20:50:03 +02002281 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2282 spec->multiout.num_dacs,
2283 spec->multiout.dac_nids[0],
2284 spec->multiout.dac_nids[1],
2285 spec->multiout.dac_nids[2],
2286 spec->multiout.dac_nids[3],
2287 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002288 return 0;
2289}
2290
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002291/* create volume control/switch for the given prefx type */
2292static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2293{
2294 char name[32];
2295 int err;
2296
2297 sprintf(name, "%s Playback Volume", pfx);
2298 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2299 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2300 if (err < 0)
2301 return err;
2302 sprintf(name, "%s Playback Switch", pfx);
2303 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2304 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2305 if (err < 0)
2306 return err;
2307 return 0;
2308}
2309
Mattc7d4b2f2005-06-27 14:59:41 +02002310/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002311static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002312 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002313{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002314 static const char *chname[4] = {
2315 "Front", "Surround", NULL /*CLFE*/, "Side"
2316 };
Mattc7d4b2f2005-06-27 14:59:41 +02002317 hda_nid_t nid;
2318 int i, err;
2319
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002320 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002321 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002322
2323
Mattc7d4b2f2005-06-27 14:59:41 +02002324 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002325 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002326 continue;
2327
2328 nid = spec->multiout.dac_nids[i];
2329
2330 if (i == 2) {
2331 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002332 err = create_controls(spec, "Center", nid, 1);
2333 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002334 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002335 err = create_controls(spec, "LFE", nid, 2);
2336 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002337 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002338
2339 wid_caps = get_wcaps(codec, nid);
2340
2341 if (wid_caps & AC_WCAP_LR_SWAP) {
2342 err = stac92xx_add_control(spec,
2343 STAC_CTL_WIDGET_CLFE_SWITCH,
2344 "Swap Center/LFE Playback Switch", nid);
2345
2346 if (err < 0)
2347 return err;
2348 }
2349
Mattc7d4b2f2005-06-27 14:59:41 +02002350 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002351 err = create_controls(spec, chname[i], nid, 3);
2352 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002353 return err;
2354 }
2355 }
2356
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002357 if (spec->line_switch) {
2358 nid = cfg->input_pins[AUTO_PIN_LINE];
2359 pincap = snd_hda_param_read(codec, nid,
2360 AC_PAR_PIN_CAP);
2361 if (pincap & AC_PINCAP_OUT) {
2362 err = stac92xx_add_control(spec,
2363 STAC_CTL_WIDGET_IO_SWITCH,
2364 "Line In as Output Switch", nid << 8);
2365 if (err < 0)
2366 return err;
2367 }
2368 }
Matt Porter403d1942005-11-29 15:00:51 +01002369
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002370 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002371 unsigned int def_conf;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002372 nid = cfg->input_pins[AUTO_PIN_MIC];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002373 def_conf = snd_hda_codec_read(codec, nid, 0,
2374 AC_VERB_GET_CONFIG_DEFAULT, 0);
2375
2376 /* some laptops have an internal analog microphone
2377 * which can't be used as a output */
2378 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2379 pincap = snd_hda_param_read(codec, nid,
2380 AC_PAR_PIN_CAP);
2381 if (pincap & AC_PINCAP_OUT) {
2382 err = stac92xx_add_control(spec,
2383 STAC_CTL_WIDGET_IO_SWITCH,
2384 "Mic as Output Switch", (nid << 8) | 1);
2385 if (err < 0)
2386 return err;
2387 }
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002388 }
2389 }
Matt Porter403d1942005-11-29 15:00:51 +01002390
Mattc7d4b2f2005-06-27 14:59:41 +02002391 return 0;
2392}
2393
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002394static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2395{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002396 if (is_in_dac_nids(spec, nid))
2397 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002398 if (spec->multiout.hp_nid == nid)
2399 return 1;
2400 return 0;
2401}
2402
2403static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2404{
2405 if (!spec->multiout.hp_nid)
2406 spec->multiout.hp_nid = nid;
2407 else if (spec->multiout.num_dacs > 4) {
2408 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2409 return 1;
2410 } else {
2411 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2412 spec->multiout.num_dacs++;
2413 }
2414 return 0;
2415}
2416
2417/* add playback controls for Speaker and HP outputs */
2418static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2419 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002420{
2421 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002422 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002423 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002424
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002425 old_num_dacs = spec->multiout.num_dacs;
2426 for (i = 0; i < cfg->hp_outs; i++) {
2427 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2428 if (wid_caps & AC_WCAP_UNSOL_CAP)
2429 spec->hp_detect = 1;
2430 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2431 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2432 if (check_in_dac_nids(spec, nid))
2433 nid = 0;
2434 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002435 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002436 add_spec_dacs(spec, nid);
2437 }
2438 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002439 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002440 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2441 if (check_in_dac_nids(spec, nid))
2442 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002443 if (! nid)
2444 continue;
2445 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002446 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002447 for (i = 0; i < cfg->line_outs; i++) {
2448 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2449 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2450 if (check_in_dac_nids(spec, nid))
2451 nid = 0;
2452 if (! nid)
2453 continue;
2454 add_spec_dacs(spec, nid);
2455 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002456 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2457 static const char *pfxs[] = {
2458 "Speaker", "External Speaker", "Speaker2",
2459 };
2460 err = create_controls(spec, pfxs[i - old_num_dacs],
2461 spec->multiout.dac_nids[i], 3);
2462 if (err < 0)
2463 return err;
2464 }
2465 if (spec->multiout.hp_nid) {
2466 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002467 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002468 pfx = "Master";
2469 else
2470 pfx = "Headphone";
2471 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2472 if (err < 0)
2473 return err;
2474 }
Mattc7d4b2f2005-06-27 14:59:41 +02002475
2476 return 0;
2477}
2478
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002479/* labels for mono mux outputs */
2480static const char *stac92xx_mono_labels[3] = {
2481 "DAC0", "DAC1", "Mixer"
2482};
2483
2484/* create mono mux for mono out on capable codecs */
2485static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2486{
2487 struct sigmatel_spec *spec = codec->spec;
2488 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2489 int i, num_cons;
2490 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2491
2492 num_cons = snd_hda_get_connections(codec,
2493 spec->mono_nid,
2494 con_lst,
2495 HDA_MAX_NUM_INPUTS);
2496 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2497 return -EINVAL;
2498
2499 for (i = 0; i < num_cons; i++) {
2500 mono_mux->items[mono_mux->num_items].label =
2501 stac92xx_mono_labels[i];
2502 mono_mux->items[mono_mux->num_items].index = i;
2503 mono_mux->num_items++;
2504 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002505
2506 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2507 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002508}
2509
Matt Porter8b657272006-10-26 17:12:59 +02002510/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002511static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002512 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2513 "Digital Mic 3", "Digital Mic 4"
2514};
2515
2516/* create playback/capture controls for input pins on dmic capable codecs */
2517static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2518 const struct auto_pin_cfg *cfg)
2519{
2520 struct sigmatel_spec *spec = codec->spec;
2521 struct hda_input_mux *dimux = &spec->private_dimux;
2522 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002523 int err, i, j;
2524 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002525
2526 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2527 dimux->items[dimux->num_items].index = 0;
2528 dimux->num_items++;
2529
2530 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002531 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002532 int index;
2533 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002534 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002535 unsigned int def_conf;
2536
2537 def_conf = snd_hda_codec_read(codec,
2538 spec->dmic_nids[i],
2539 0,
2540 AC_VERB_GET_CONFIG_DEFAULT,
2541 0);
2542 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2543 continue;
2544
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002545 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002546 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002547 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002548 con_lst,
2549 HDA_MAX_NUM_INPUTS);
2550 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002551 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002552 index = j;
2553 goto found;
2554 }
2555 continue;
2556found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002557 wcaps = get_wcaps(codec, nid);
2558
2559 if (wcaps & AC_WCAP_OUT_AMP) {
2560 sprintf(name, "%s Capture Volume",
2561 stac92xx_dmic_labels[dimux->num_items]);
2562
2563 err = stac92xx_add_control(spec,
2564 STAC_CTL_WIDGET_VOL,
2565 name,
2566 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2567 if (err < 0)
2568 return err;
2569 }
2570
Matt Porter8b657272006-10-26 17:12:59 +02002571 dimux->items[dimux->num_items].label =
2572 stac92xx_dmic_labels[dimux->num_items];
2573 dimux->items[dimux->num_items].index = index;
2574 dimux->num_items++;
2575 }
2576
2577 return 0;
2578}
2579
Mattc7d4b2f2005-06-27 14:59:41 +02002580/* create playback/capture controls for input pins */
2581static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2582{
2583 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002584 struct hda_input_mux *imux = &spec->private_imux;
2585 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2586 int i, j, k;
2587
2588 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002589 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002590
Takashi Iwai314634b2006-09-21 11:56:18 +02002591 if (!cfg->input_pins[i])
2592 continue;
2593 index = -1;
2594 for (j = 0; j < spec->num_muxes; j++) {
2595 int num_cons;
2596 num_cons = snd_hda_get_connections(codec,
2597 spec->mux_nids[j],
2598 con_lst,
2599 HDA_MAX_NUM_INPUTS);
2600 for (k = 0; k < num_cons; k++)
2601 if (con_lst[k] == cfg->input_pins[i]) {
2602 index = k;
2603 goto found;
2604 }
Mattc7d4b2f2005-06-27 14:59:41 +02002605 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002606 continue;
2607 found:
2608 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2609 imux->items[imux->num_items].index = index;
2610 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002611 }
2612
Steve Longerbeam7b043892007-05-03 20:50:03 +02002613 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002614 /*
2615 * Set the current input for the muxes.
2616 * The STAC9221 has two input muxes with identical source
2617 * NID lists. Hopefully this won't get confused.
2618 */
2619 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002620 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2621 AC_VERB_SET_CONNECT_SEL,
2622 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002623 }
2624 }
2625
Mattc7d4b2f2005-06-27 14:59:41 +02002626 return 0;
2627}
2628
Mattc7d4b2f2005-06-27 14:59:41 +02002629static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2630{
2631 struct sigmatel_spec *spec = codec->spec;
2632 int i;
2633
2634 for (i = 0; i < spec->autocfg.line_outs; i++) {
2635 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2636 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2637 }
2638}
2639
2640static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2641{
2642 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002643 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002644
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002645 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2646 hda_nid_t pin;
2647 pin = spec->autocfg.hp_pins[i];
2648 if (pin) /* connect to front */
2649 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2650 }
2651 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2652 hda_nid_t pin;
2653 pin = spec->autocfg.speaker_pins[i];
2654 if (pin) /* connect to front */
2655 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2656 }
Mattc7d4b2f2005-06-27 14:59:41 +02002657}
2658
Matt Porter3cc08dc2006-01-23 15:27:49 +01002659static 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 +02002660{
2661 struct sigmatel_spec *spec = codec->spec;
2662 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002663 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002664
Matt Porter8b657272006-10-26 17:12:59 +02002665 if ((err = snd_hda_parse_pin_def_config(codec,
2666 &spec->autocfg,
2667 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002668 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002669 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002670 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002671
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002672 /* If we have no real line-out pin and multiple hp-outs, HPs should
2673 * be set up as multi-channel outputs.
2674 */
2675 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2676 spec->autocfg.hp_outs > 1) {
2677 /* Copy hp_outs to line_outs, backup line_outs in
2678 * speaker_outs so that the following routines can handle
2679 * HP pins as primary outputs.
2680 */
2681 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2682 sizeof(spec->autocfg.line_out_pins));
2683 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2684 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2685 sizeof(spec->autocfg.hp_pins));
2686 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2687 hp_speaker_swap = 1;
2688 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002689 if (spec->autocfg.mono_out_pin) {
2690 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2691 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2692 u32 caps = query_amp_caps(codec,
2693 spec->autocfg.mono_out_pin, dir);
2694 hda_nid_t conn_list[1];
2695
2696 /* get the mixer node and then the mono mux if it exists */
2697 if (snd_hda_get_connections(codec,
2698 spec->autocfg.mono_out_pin, conn_list, 1) &&
2699 snd_hda_get_connections(codec, conn_list[0],
2700 conn_list, 1)) {
2701
2702 int wcaps = get_wcaps(codec, conn_list[0]);
2703 int wid_type = (wcaps & AC_WCAP_TYPE)
2704 >> AC_WCAP_TYPE_SHIFT;
2705 /* LR swap check, some stac925x have a mux that
2706 * changes the DACs output path instead of the
2707 * mono-mux path.
2708 */
2709 if (wid_type == AC_WID_AUD_SEL &&
2710 !(wcaps & AC_WCAP_LR_SWAP))
2711 spec->mono_nid = conn_list[0];
2712 }
2713 /* all mono outs have a least a mute/unmute switch */
2714 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2715 "Mono Playback Switch",
2716 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2717 1, 0, dir));
2718 if (err < 0)
2719 return err;
2720 /* check to see if there is volume support for the amp */
2721 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2722 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2723 "Mono Playback Volume",
2724 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2725 1, 0, dir));
2726 if (err < 0)
2727 return err;
2728 }
2729
2730 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2731 AC_PINCTL_OUT_EN);
2732 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002733
Matt Porter403d1942005-11-29 15:00:51 +01002734 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2735 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002736 if (spec->multiout.num_dacs == 0)
2737 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2738 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002739
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002740 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2741
2742 if (err < 0)
2743 return err;
2744
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002745 if (hp_speaker_swap == 1) {
2746 /* Restore the hp_outs and line_outs */
2747 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2748 sizeof(spec->autocfg.line_out_pins));
2749 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2750 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2751 sizeof(spec->autocfg.speaker_pins));
2752 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2753 memset(spec->autocfg.speaker_pins, 0,
2754 sizeof(spec->autocfg.speaker_pins));
2755 spec->autocfg.speaker_outs = 0;
2756 }
2757
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002758 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2759
2760 if (err < 0)
2761 return err;
2762
2763 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2764
2765 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002766 return err;
2767
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002768 if (spec->mono_nid > 0) {
2769 err = stac92xx_auto_create_mono_output_ctls(codec);
2770 if (err < 0)
2771 return err;
2772 }
2773
Matt Porter8b657272006-10-26 17:12:59 +02002774 if (spec->num_dmics > 0)
2775 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2776 &spec->autocfg)) < 0)
2777 return err;
2778
Mattc7d4b2f2005-06-27 14:59:41 +02002779 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002780 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002781 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002782
Takashi Iwai82bc9552006-03-21 11:24:42 +01002783 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002784 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002785 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002786 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002787
2788 if (spec->kctl_alloc)
2789 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2790
2791 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002792 if (!spec->dinput_mux)
2793 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002794 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002795
2796 return 1;
2797}
2798
Takashi Iwai82bc9552006-03-21 11:24:42 +01002799/* add playback controls for HP output */
2800static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2801 struct auto_pin_cfg *cfg)
2802{
2803 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002804 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002805 unsigned int wid_caps;
2806
2807 if (! pin)
2808 return 0;
2809
2810 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002811 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002812 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002813
2814 return 0;
2815}
2816
Richard Fish160ea0d2006-09-06 13:58:25 +02002817/* add playback controls for LFE output */
2818static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2819 struct auto_pin_cfg *cfg)
2820{
2821 struct sigmatel_spec *spec = codec->spec;
2822 int err;
2823 hda_nid_t lfe_pin = 0x0;
2824 int i;
2825
2826 /*
2827 * search speaker outs and line outs for a mono speaker pin
2828 * with an amp. If one is found, add LFE controls
2829 * for it.
2830 */
2831 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2832 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2833 unsigned long wcaps = get_wcaps(codec, pin);
2834 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2835 if (wcaps == AC_WCAP_OUT_AMP)
2836 /* found a mono speaker with an amp, must be lfe */
2837 lfe_pin = pin;
2838 }
2839
2840 /* if speaker_outs is 0, then speakers may be in line_outs */
2841 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2842 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2843 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2844 unsigned long cfg;
2845 cfg = snd_hda_codec_read(codec, pin, 0,
2846 AC_VERB_GET_CONFIG_DEFAULT,
2847 0x00);
2848 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2849 unsigned long wcaps = get_wcaps(codec, pin);
2850 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2851 if (wcaps == AC_WCAP_OUT_AMP)
2852 /* found a mono speaker with an amp,
2853 must be lfe */
2854 lfe_pin = pin;
2855 }
2856 }
2857 }
2858
2859 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002860 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002861 if (err < 0)
2862 return err;
2863 }
2864
2865 return 0;
2866}
2867
Mattc7d4b2f2005-06-27 14:59:41 +02002868static int stac9200_parse_auto_config(struct hda_codec *codec)
2869{
2870 struct sigmatel_spec *spec = codec->spec;
2871 int err;
2872
Kailang Yangdf694da2005-12-05 19:42:22 +01002873 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002874 return err;
2875
2876 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2877 return err;
2878
Takashi Iwai82bc9552006-03-21 11:24:42 +01002879 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2880 return err;
2881
Richard Fish160ea0d2006-09-06 13:58:25 +02002882 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2883 return err;
2884
Takashi Iwai82bc9552006-03-21 11:24:42 +01002885 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002886 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002887 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002888 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002889
2890 if (spec->kctl_alloc)
2891 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2892
2893 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002894 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002895
2896 return 1;
2897}
2898
Sam Revitch62fe78e2006-05-10 15:09:17 +02002899/*
2900 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2901 * funky external mute control using GPIO pins.
2902 */
2903
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002904static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002905 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002906{
2907 unsigned int gpiostate, gpiomask, gpiodir;
2908
2909 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2910 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002911 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002912
2913 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2914 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002915 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002916
2917 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2918 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002919 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002920
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002921 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002922 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2923
2924 snd_hda_codec_write(codec, codec->afg, 0,
2925 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002926 snd_hda_codec_read(codec, codec->afg, 0,
2927 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002928
2929 msleep(1);
2930
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002931 snd_hda_codec_read(codec, codec->afg, 0,
2932 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002933}
2934
Takashi Iwai314634b2006-09-21 11:56:18 +02002935static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2936 unsigned int event)
2937{
2938 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002939 snd_hda_codec_write_cache(codec, nid, 0,
2940 AC_VERB_SET_UNSOLICITED_ENABLE,
2941 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002942}
2943
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002944static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2945{
2946 int i;
2947 for (i = 0; i < cfg->hp_outs; i++)
2948 if (cfg->hp_pins[i] == nid)
2949 return 1; /* nid is a HP-Out */
2950
2951 return 0; /* nid is not a HP-Out */
2952};
2953
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002954static void stac92xx_power_down(struct hda_codec *codec)
2955{
2956 struct sigmatel_spec *spec = codec->spec;
2957
2958 /* power down inactive DACs */
2959 hda_nid_t *dac;
2960 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01002961 if (!is_in_dac_nids(spec, *dac) &&
2962 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002963 snd_hda_codec_write_cache(codec, *dac, 0,
2964 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
2965}
2966
Mattc7d4b2f2005-06-27 14:59:41 +02002967static int stac92xx_init(struct hda_codec *codec)
2968{
2969 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002970 struct auto_pin_cfg *cfg = &spec->autocfg;
2971 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002972
Mattc7d4b2f2005-06-27 14:59:41 +02002973 snd_hda_sequence_write(codec, spec->init);
2974
Takashi Iwai82bc9552006-03-21 11:24:42 +01002975 /* set up pins */
2976 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002977 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002978 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002979 enable_pin_detect(codec, cfg->hp_pins[i],
2980 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002981 /* force to enable the first line-out; the others are set up
2982 * in unsol_event
2983 */
2984 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2985 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002986 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002987 /* fake event to set up pins */
2988 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2989 } else {
2990 stac92xx_auto_init_multi_out(codec);
2991 stac92xx_auto_init_hp_out(codec);
2992 }
2993 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002994 hda_nid_t nid = cfg->input_pins[i];
2995 if (nid) {
2996 unsigned int pinctl = AC_PINCTL_IN_EN;
2997 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2998 pinctl |= stac92xx_get_vref(codec, nid);
2999 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3000 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003001 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003002 for (i = 0; i < spec->num_dmics; i++)
3003 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3004 AC_PINCTL_IN_EN);
3005 for (i = 0; i < spec->num_pwrs; i++) {
3006 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3007 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3008 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3009 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3010 /* outputs are only ports capable of power management
3011 * any attempts on powering down a input port cause the
3012 * referenced VREF to act quirky.
3013 */
3014 if (pinctl & AC_PINCTL_IN_EN)
3015 continue;
3016 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3017 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3018 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003019 if (spec->dac_list)
3020 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003021 if (cfg->dig_out_pin)
3022 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3023 AC_PINCTL_OUT_EN);
3024 if (cfg->dig_in_pin)
3025 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3026 AC_PINCTL_IN_EN);
3027
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003028 stac_gpio_set(codec, spec->gpio_mask,
3029 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003030
Mattc7d4b2f2005-06-27 14:59:41 +02003031 return 0;
3032}
3033
Matt2f2f4252005-04-13 14:45:30 +02003034static void stac92xx_free(struct hda_codec *codec)
3035{
Mattc7d4b2f2005-06-27 14:59:41 +02003036 struct sigmatel_spec *spec = codec->spec;
3037 int i;
3038
3039 if (! spec)
3040 return;
3041
3042 if (spec->kctl_alloc) {
3043 for (i = 0; i < spec->num_kctl_used; i++)
3044 kfree(spec->kctl_alloc[i].name);
3045 kfree(spec->kctl_alloc);
3046 }
3047
Richard Fish11b44bb2006-08-23 18:31:34 +02003048 if (spec->bios_pin_configs)
3049 kfree(spec->bios_pin_configs);
3050
Mattc7d4b2f2005-06-27 14:59:41 +02003051 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02003052}
3053
Matt4e550962005-07-04 17:51:39 +02003054static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3055 unsigned int flag)
3056{
3057 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3058 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003059
Takashi Iwaif9acba42007-05-29 18:01:06 +02003060 if (pin_ctl & AC_PINCTL_IN_EN) {
3061 /*
3062 * we need to check the current set-up direction of
3063 * shared input pins since they can be switched via
3064 * "xxx as Output" mixer switch
3065 */
3066 struct sigmatel_spec *spec = codec->spec;
3067 struct auto_pin_cfg *cfg = &spec->autocfg;
3068 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3069 spec->line_switch) ||
3070 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3071 spec->mic_switch))
3072 return;
3073 }
3074
Steve Longerbeam7b043892007-05-03 20:50:03 +02003075 /* if setting pin direction bits, clear the current
3076 direction bits first */
3077 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3078 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3079
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003080 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003081 AC_VERB_SET_PIN_WIDGET_CONTROL,
3082 pin_ctl | flag);
3083}
3084
3085static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3086 unsigned int flag)
3087{
3088 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3089 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003090 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003091 AC_VERB_SET_PIN_WIDGET_CONTROL,
3092 pin_ctl & ~flag);
3093}
3094
Jiang Zhe40c1d302007-11-12 13:05:16 +01003095static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003096{
3097 if (!nid)
3098 return 0;
3099 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003100 & (1 << 31)) {
3101 unsigned int pinctl;
3102 pinctl = snd_hda_codec_read(codec, nid, 0,
3103 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3104 if (pinctl & AC_PINCTL_IN_EN)
3105 return 0; /* mic- or line-input */
3106 else
3107 return 1; /* HP-output */
3108 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003109 return 0;
3110}
3111
3112static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003113{
3114 struct sigmatel_spec *spec = codec->spec;
3115 struct auto_pin_cfg *cfg = &spec->autocfg;
3116 int i, presence;
3117
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003118 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003119 if (spec->gpio_mute)
3120 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3121 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3122
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003123 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003124 if (presence)
3125 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003126 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003127 }
Matt4e550962005-07-04 17:51:39 +02003128
3129 if (presence) {
3130 /* disable lineouts, enable hp */
3131 for (i = 0; i < cfg->line_outs; i++)
3132 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3133 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003134 for (i = 0; i < cfg->speaker_outs; i++)
3135 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3136 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003137 } else {
3138 /* enable lineouts, disable hp */
3139 for (i = 0; i < cfg->line_outs; i++)
3140 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3141 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003142 for (i = 0; i < cfg->speaker_outs; i++)
3143 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3144 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003145 }
3146}
3147
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003148static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3149{
3150 struct sigmatel_spec *spec = codec->spec;
3151 hda_nid_t nid = spec->pwr_nids[idx];
3152 int presence, val;
3153 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3154 & 0x000000ff;
3155 presence = get_hp_pin_presence(codec, nid);
3156 idx = 1 << idx;
3157
3158 if (presence)
3159 val &= ~idx;
3160 else
3161 val |= idx;
3162
3163 /* power down unused output ports */
3164 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3165};
3166
Takashi Iwai314634b2006-09-21 11:56:18 +02003167static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3168{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003169 struct sigmatel_spec *spec = codec->spec;
3170 int idx = res >> 26 & 0x0f;
3171
3172 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003173 case STAC_HP_EVENT:
3174 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003175 /* fallthru */
3176 case STAC_PWR_EVENT:
3177 if (spec->num_pwrs > 0)
3178 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003179 }
3180}
3181
Takashi Iwaicb53c622007-08-10 17:21:45 +02003182#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003183static int stac92xx_resume(struct hda_codec *codec)
3184{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003185 struct sigmatel_spec *spec = codec->spec;
3186
Richard Fish11b44bb2006-08-23 18:31:34 +02003187 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003188 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003189 stac_gpio_set(codec, spec->gpio_mask,
3190 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003191 snd_hda_codec_resume_amp(codec);
3192 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003193 /* power down inactive DACs */
3194 if (spec->dac_list)
3195 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003196 /* invoke unsolicited event to reset the HP state */
3197 if (spec->hp_detect)
3198 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003199 return 0;
3200}
3201#endif
3202
Matt2f2f4252005-04-13 14:45:30 +02003203static struct hda_codec_ops stac92xx_patch_ops = {
3204 .build_controls = stac92xx_build_controls,
3205 .build_pcms = stac92xx_build_pcms,
3206 .init = stac92xx_init,
3207 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003208 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003209#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003210 .resume = stac92xx_resume,
3211#endif
Matt2f2f4252005-04-13 14:45:30 +02003212};
3213
3214static int patch_stac9200(struct hda_codec *codec)
3215{
3216 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003217 int err;
Matt2f2f4252005-04-13 14:45:30 +02003218
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003219 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003220 if (spec == NULL)
3221 return -ENOMEM;
3222
3223 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003224 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003225 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003226 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3227 stac9200_models,
3228 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003229 if (spec->board_config < 0) {
3230 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3231 err = stac92xx_save_bios_config_regs(codec);
3232 if (err < 0) {
3233 stac92xx_free(codec);
3234 return err;
3235 }
3236 spec->pin_configs = spec->bios_pin_configs;
3237 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003238 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3239 stac92xx_set_config_regs(codec);
3240 }
Matt2f2f4252005-04-13 14:45:30 +02003241
3242 spec->multiout.max_channels = 2;
3243 spec->multiout.num_dacs = 1;
3244 spec->multiout.dac_nids = stac9200_dac_nids;
3245 spec->adc_nids = stac9200_adc_nids;
3246 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003247 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003248 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003249 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003250 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003251
Tobin Davisbf277782008-02-03 20:31:47 +01003252 if (spec->board_config == STAC_9200_GATEWAY ||
3253 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003254 spec->init = stac9200_eapd_init;
3255 else
3256 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003257 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003258
3259 err = stac9200_parse_auto_config(codec);
3260 if (err < 0) {
3261 stac92xx_free(codec);
3262 return err;
3263 }
Matt2f2f4252005-04-13 14:45:30 +02003264
3265 codec->patch_ops = stac92xx_patch_ops;
3266
3267 return 0;
3268}
3269
Tobin Davis8e21c342007-01-08 11:04:17 +01003270static int patch_stac925x(struct hda_codec *codec)
3271{
3272 struct sigmatel_spec *spec;
3273 int err;
3274
3275 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3276 if (spec == NULL)
3277 return -ENOMEM;
3278
3279 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003280 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003281 spec->pin_nids = stac925x_pin_nids;
3282 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3283 stac925x_models,
3284 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003285 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003286 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003287 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3288 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003289 err = stac92xx_save_bios_config_regs(codec);
3290 if (err < 0) {
3291 stac92xx_free(codec);
3292 return err;
3293 }
3294 spec->pin_configs = spec->bios_pin_configs;
3295 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3296 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3297 stac92xx_set_config_regs(codec);
3298 }
3299
3300 spec->multiout.max_channels = 2;
3301 spec->multiout.num_dacs = 1;
3302 spec->multiout.dac_nids = stac925x_dac_nids;
3303 spec->adc_nids = stac925x_adc_nids;
3304 spec->mux_nids = stac925x_mux_nids;
3305 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003306 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003307 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003308 switch (codec->vendor_id) {
3309 case 0x83847632: /* STAC9202 */
3310 case 0x83847633: /* STAC9202D */
3311 case 0x83847636: /* STAC9251 */
3312 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003313 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003314 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003315 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3316 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003317 break;
3318 default:
3319 spec->num_dmics = 0;
3320 break;
3321 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003322
3323 spec->init = stac925x_core_init;
3324 spec->mixer = stac925x_mixer;
3325
3326 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003327 if (!err) {
3328 if (spec->board_config < 0) {
3329 printk(KERN_WARNING "hda_codec: No auto-config is "
3330 "available, default to model=ref\n");
3331 spec->board_config = STAC_925x_REF;
3332 goto again;
3333 }
3334 err = -EINVAL;
3335 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003336 if (err < 0) {
3337 stac92xx_free(codec);
3338 return err;
3339 }
3340
3341 codec->patch_ops = stac92xx_patch_ops;
3342
3343 return 0;
3344}
3345
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003346static struct hda_input_mux stac92hd73xx_dmux = {
3347 .num_items = 4,
3348 .items = {
3349 { "Analog Inputs", 0x0b },
3350 { "CD", 0x08 },
3351 { "Digital Mic 1", 0x09 },
3352 { "Digital Mic 2", 0x0a },
3353 }
3354};
3355
3356static int patch_stac92hd73xx(struct hda_codec *codec)
3357{
3358 struct sigmatel_spec *spec;
3359 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3360 int err = 0;
3361
3362 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3363 if (spec == NULL)
3364 return -ENOMEM;
3365
3366 codec->spec = spec;
3367 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3368 spec->pin_nids = stac92hd73xx_pin_nids;
3369 spec->board_config = snd_hda_check_board_config(codec,
3370 STAC_92HD73XX_MODELS,
3371 stac92hd73xx_models,
3372 stac92hd73xx_cfg_tbl);
3373again:
3374 if (spec->board_config < 0) {
3375 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3376 " STAC92HD73XX, using BIOS defaults\n");
3377 err = stac92xx_save_bios_config_regs(codec);
3378 if (err < 0) {
3379 stac92xx_free(codec);
3380 return err;
3381 }
3382 spec->pin_configs = spec->bios_pin_configs;
3383 } else {
3384 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3385 stac92xx_set_config_regs(codec);
3386 }
3387
3388 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3389 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3390
3391 if (spec->multiout.num_dacs < 0) {
3392 printk(KERN_WARNING "hda_codec: Could not determine "
3393 "number of channels defaulting to DAC count\n");
3394 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3395 }
3396
3397 switch (spec->multiout.num_dacs) {
3398 case 0x3: /* 6 Channel */
3399 spec->mixer = stac92hd73xx_6ch_mixer;
3400 spec->init = stac92hd73xx_6ch_core_init;
3401 break;
3402 case 0x4: /* 8 Channel */
3403 spec->multiout.hp_nid = 0x18;
3404 spec->mixer = stac92hd73xx_8ch_mixer;
3405 spec->init = stac92hd73xx_8ch_core_init;
3406 break;
3407 case 0x5: /* 10 Channel */
3408 spec->multiout.hp_nid = 0x19;
3409 spec->mixer = stac92hd73xx_10ch_mixer;
3410 spec->init = stac92hd73xx_10ch_core_init;
3411 };
3412
3413 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3414 spec->aloopback_mask = 0x01;
3415 spec->aloopback_shift = 8;
3416
3417 spec->mux_nids = stac92hd73xx_mux_nids;
3418 spec->adc_nids = stac92hd73xx_adc_nids;
3419 spec->dmic_nids = stac92hd73xx_dmic_nids;
3420 spec->dmux_nids = stac92hd73xx_dmux_nids;
3421
3422 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3423 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003424 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003425 spec->dinput_mux = &stac92hd73xx_dmux;
3426 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003427 spec->gpio_mask = spec->gpio_dir = 0x1;
3428 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003429
Matthew Ranostaya7662642008-02-21 07:51:14 +01003430 switch (spec->board_config) {
3431 case STAC_DELL_M6:
3432 switch (codec->subsystem_id) {
3433 case 0x1028025e: /* Analog Mics */
3434 case 0x1028025f:
3435 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3436 spec->num_dmics = 0;
3437 break;
3438 case 0x10280254: /* Digital Mics */
3439 case 0x10280255:
3440 case 0x10280271:
3441 case 0x10280272:
3442 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3443 spec->num_dmics = 1;
3444 break;
3445 case 0x10280256: /* Both */
3446 case 0x10280057:
3447 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3448 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3449 spec->num_dmics = 1;
3450 break;
3451 }
3452 break;
3453 default:
3454 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3455 }
3456
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003457 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3458 spec->pwr_nids = stac92hd73xx_pwr_nids;
3459
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003460 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3461
3462 if (!err) {
3463 if (spec->board_config < 0) {
3464 printk(KERN_WARNING "hda_codec: No auto-config is "
3465 "available, default to model=ref\n");
3466 spec->board_config = STAC_92HD73XX_REF;
3467 goto again;
3468 }
3469 err = -EINVAL;
3470 }
3471
3472 if (err < 0) {
3473 stac92xx_free(codec);
3474 return err;
3475 }
3476
3477 codec->patch_ops = stac92xx_patch_ops;
3478
3479 return 0;
3480}
3481
Matthew Ranostaye035b842007-11-06 11:53:55 +01003482static int patch_stac92hd71bxx(struct hda_codec *codec)
3483{
3484 struct sigmatel_spec *spec;
3485 int err = 0;
3486
3487 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3488 if (spec == NULL)
3489 return -ENOMEM;
3490
3491 codec->spec = spec;
3492 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3493 spec->pin_nids = stac92hd71bxx_pin_nids;
3494 spec->board_config = snd_hda_check_board_config(codec,
3495 STAC_92HD71BXX_MODELS,
3496 stac92hd71bxx_models,
3497 stac92hd71bxx_cfg_tbl);
3498again:
3499 if (spec->board_config < 0) {
3500 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3501 " STAC92HD71BXX, using BIOS defaults\n");
3502 err = stac92xx_save_bios_config_regs(codec);
3503 if (err < 0) {
3504 stac92xx_free(codec);
3505 return err;
3506 }
3507 spec->pin_configs = spec->bios_pin_configs;
3508 } else {
3509 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3510 stac92xx_set_config_regs(codec);
3511 }
3512
Matthew Ranostay541eee82007-12-14 12:08:04 +01003513 switch (codec->vendor_id) {
3514 case 0x111d76b6: /* 4 Port without Analog Mixer */
3515 case 0x111d76b7:
3516 case 0x111d76b4: /* 6 Port without Analog Mixer */
3517 case 0x111d76b5:
3518 spec->mixer = stac92hd71bxx_mixer;
3519 spec->init = stac92hd71bxx_core_init;
3520 break;
3521 default:
3522 spec->mixer = stac92hd71bxx_analog_mixer;
3523 spec->init = stac92hd71bxx_analog_core_init;
3524 }
3525
3526 spec->aloopback_mask = 0x20;
3527 spec->aloopback_shift = 0;
3528
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003529 /* GPIO0 High = EAPD */
3530 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003531
Matthew Ranostaye035b842007-11-06 11:53:55 +01003532 spec->mux_nids = stac92hd71bxx_mux_nids;
3533 spec->adc_nids = stac92hd71bxx_adc_nids;
3534 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003535 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003536
3537 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3538 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3539 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003540 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003541
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003542 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3543 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3544
Matthew Ranostaye035b842007-11-06 11:53:55 +01003545 spec->multiout.num_dacs = 2;
3546 spec->multiout.hp_nid = 0x11;
3547 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3548
3549 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3550 if (!err) {
3551 if (spec->board_config < 0) {
3552 printk(KERN_WARNING "hda_codec: No auto-config is "
3553 "available, default to model=ref\n");
3554 spec->board_config = STAC_92HD71BXX_REF;
3555 goto again;
3556 }
3557 err = -EINVAL;
3558 }
3559
3560 if (err < 0) {
3561 stac92xx_free(codec);
3562 return err;
3563 }
3564
3565 codec->patch_ops = stac92xx_patch_ops;
3566
3567 return 0;
3568};
3569
Matt2f2f4252005-04-13 14:45:30 +02003570static int patch_stac922x(struct hda_codec *codec)
3571{
3572 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003573 int err;
Matt2f2f4252005-04-13 14:45:30 +02003574
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003575 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003576 if (spec == NULL)
3577 return -ENOMEM;
3578
3579 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003580 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003581 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003582 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3583 stac922x_models,
3584 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003585 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003586 spec->gpio_mask = spec->gpio_dir = 0x03;
3587 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003588 /* Intel Macs have all same PCI SSID, so we need to check
3589 * codec SSID to distinguish the exact models
3590 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003591 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003592 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003593
3594 case 0x106b0800:
3595 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003596 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003597 case 0x106b0600:
3598 case 0x106b0700:
3599 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003600 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003601 case 0x106b0e00:
3602 case 0x106b0f00:
3603 case 0x106b1600:
3604 case 0x106b1700:
3605 case 0x106b0200:
3606 case 0x106b1e00:
3607 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003608 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003609 case 0x106b1a00:
3610 case 0x00000100:
3611 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003612 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003613 case 0x106b0a00:
3614 case 0x106b2200:
3615 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003616 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003617 }
3618 }
3619
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003620 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003621 if (spec->board_config < 0) {
3622 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3623 "using BIOS defaults\n");
3624 err = stac92xx_save_bios_config_regs(codec);
3625 if (err < 0) {
3626 stac92xx_free(codec);
3627 return err;
3628 }
3629 spec->pin_configs = spec->bios_pin_configs;
3630 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003631 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3632 stac92xx_set_config_regs(codec);
3633 }
Matt2f2f4252005-04-13 14:45:30 +02003634
Matt2f2f4252005-04-13 14:45:30 +02003635 spec->adc_nids = stac922x_adc_nids;
3636 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003637 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003638 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003639 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003640 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003641
3642 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003643 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003644
3645 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003646
Matt Porter3cc08dc2006-01-23 15:27:49 +01003647 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003648 if (!err) {
3649 if (spec->board_config < 0) {
3650 printk(KERN_WARNING "hda_codec: No auto-config is "
3651 "available, default to model=ref\n");
3652 spec->board_config = STAC_D945_REF;
3653 goto again;
3654 }
3655 err = -EINVAL;
3656 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003657 if (err < 0) {
3658 stac92xx_free(codec);
3659 return err;
3660 }
3661
3662 codec->patch_ops = stac92xx_patch_ops;
3663
Takashi Iwai807a46362007-05-29 19:01:37 +02003664 /* Fix Mux capture level; max to 2 */
3665 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3666 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3667 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3668 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3669 (0 << AC_AMPCAP_MUTE_SHIFT));
3670
Matt Porter3cc08dc2006-01-23 15:27:49 +01003671 return 0;
3672}
3673
3674static int patch_stac927x(struct hda_codec *codec)
3675{
3676 struct sigmatel_spec *spec;
3677 int err;
3678
3679 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3680 if (spec == NULL)
3681 return -ENOMEM;
3682
3683 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003684 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003685 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003686 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3687 stac927x_models,
3688 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003689 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003690 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3691 if (spec->board_config < 0)
3692 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3693 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003694 err = stac92xx_save_bios_config_regs(codec);
3695 if (err < 0) {
3696 stac92xx_free(codec);
3697 return err;
3698 }
3699 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003700 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003701 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3702 stac92xx_set_config_regs(codec);
3703 }
3704
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003705 spec->adc_nids = stac927x_adc_nids;
3706 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3707 spec->mux_nids = stac927x_mux_nids;
3708 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003709 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003710 spec->multiout.dac_nids = spec->dac_nids;
3711
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003712 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003713 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003714 case STAC_D965_5ST:
3715 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003716 spec->gpio_mask = spec->gpio_dir = 0x01;
3717 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003718 spec->num_dmics = 0;
3719
Tobin Davis93ed1502006-09-01 21:03:12 +02003720 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003721 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003722 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003723 case STAC_DELL_BIOS:
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003724 /* configure the analog microphone on some laptops */
3725 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003726 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003727 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003728 /* correct the front input jack as a mic */
3729 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3730 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003731 case STAC_DELL_3ST:
3732 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003733 spec->gpio_mask = spec->gpio_dir = 0x04;
3734 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003735 spec->dmic_nids = stac927x_dmic_nids;
3736 spec->num_dmics = STAC927X_NUM_DMICS;
3737
Tobin Davis93ed1502006-09-01 21:03:12 +02003738 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003739 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003740 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003741 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003742 break;
3743 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003744 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003745 spec->gpio_mask = spec->gpio_dir = 0x1;
3746 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003747 spec->num_dmics = 0;
3748
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003749 spec->init = stac927x_core_init;
3750 spec->mixer = stac927x_mixer;
3751 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003752
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003753 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003754 spec->aloopback_mask = 0x40;
3755 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003756
Matt Porter3cc08dc2006-01-23 15:27:49 +01003757 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003758 if (!err) {
3759 if (spec->board_config < 0) {
3760 printk(KERN_WARNING "hda_codec: No auto-config is "
3761 "available, default to model=ref\n");
3762 spec->board_config = STAC_D965_REF;
3763 goto again;
3764 }
3765 err = -EINVAL;
3766 }
Mattc7d4b2f2005-06-27 14:59:41 +02003767 if (err < 0) {
3768 stac92xx_free(codec);
3769 return err;
3770 }
Matt2f2f4252005-04-13 14:45:30 +02003771
3772 codec->patch_ops = stac92xx_patch_ops;
3773
Takashi Iwai52987652008-01-16 16:09:47 +01003774 /*
3775 * !!FIXME!!
3776 * The STAC927x seem to require fairly long delays for certain
3777 * command sequences. With too short delays (even if the answer
3778 * is set to RIRB properly), it results in the silence output
3779 * on some hardwares like Dell.
3780 *
3781 * The below flag enables the longer delay (see get_response
3782 * in hda_intel.c).
3783 */
3784 codec->bus->needs_damn_long_delay = 1;
3785
Matt2f2f4252005-04-13 14:45:30 +02003786 return 0;
3787}
3788
Matt Porterf3302a52006-07-31 12:49:34 +02003789static int patch_stac9205(struct hda_codec *codec)
3790{
3791 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003792 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003793
3794 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3795 if (spec == NULL)
3796 return -ENOMEM;
3797
3798 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003799 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003800 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003801 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3802 stac9205_models,
3803 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003804 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003805 if (spec->board_config < 0) {
3806 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3807 err = stac92xx_save_bios_config_regs(codec);
3808 if (err < 0) {
3809 stac92xx_free(codec);
3810 return err;
3811 }
3812 spec->pin_configs = spec->bios_pin_configs;
3813 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003814 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3815 stac92xx_set_config_regs(codec);
3816 }
3817
3818 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003819 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003820 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003821 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003822 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003823 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003824 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003825 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003826 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003827
3828 spec->init = stac9205_core_init;
3829 spec->mixer = stac9205_mixer;
3830
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003831 spec->aloopback_mask = 0x40;
3832 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003833 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003834
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003835 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003836 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003837 /* Enable SPDIF in/out */
3838 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3839 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003840
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003841 /* Enable unsol response for GPIO4/Dock HP connection */
3842 snd_hda_codec_write(codec, codec->afg, 0,
3843 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3844 snd_hda_codec_write_cache(codec, codec->afg, 0,
3845 AC_VERB_SET_UNSOLICITED_ENABLE,
3846 (AC_USRSP_EN | STAC_HP_EVENT));
3847
3848 spec->gpio_dir = 0x0b;
3849 spec->gpio_mask = 0x1b;
3850 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003851 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003852 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003853 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003854 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003855 break;
3856 default:
3857 /* GPIO0 High = EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003858 spec->gpio_mask = spec->gpio_dir = 0x1;
3859 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003860 break;
3861 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003862
Matt Porterf3302a52006-07-31 12:49:34 +02003863 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003864 if (!err) {
3865 if (spec->board_config < 0) {
3866 printk(KERN_WARNING "hda_codec: No auto-config is "
3867 "available, default to model=ref\n");
3868 spec->board_config = STAC_9205_REF;
3869 goto again;
3870 }
3871 err = -EINVAL;
3872 }
Matt Porterf3302a52006-07-31 12:49:34 +02003873 if (err < 0) {
3874 stac92xx_free(codec);
3875 return err;
3876 }
3877
3878 codec->patch_ops = stac92xx_patch_ops;
3879
3880 return 0;
3881}
3882
Matt2f2f4252005-04-13 14:45:30 +02003883/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003884 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003885 */
3886
Guillaume Munch99ccc562006-08-16 19:35:12 +02003887/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003888static hda_nid_t vaio_dacs[] = { 0x2 };
3889#define VAIO_HP_DAC 0x5
3890static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3891static hda_nid_t vaio_mux_nids[] = { 0x15 };
3892
3893static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003894 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003895 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003896 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003897 { "Mic Jack", 0x1 },
3898 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003899 { "PCM", 0x3 },
3900 }
3901};
3902
3903static struct hda_verb vaio_init[] = {
3904 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003905 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003906 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3907 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3908 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3909 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003910 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003911 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3912 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3913 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3914 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3915 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3916 {}
3917};
3918
Guillaume Munch6d859062006-08-22 17:15:47 +02003919static struct hda_verb vaio_ar_init[] = {
3920 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3921 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3922 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3923 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3924/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3925 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003926 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003927 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3928 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3929/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3930 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3931 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3932 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3933 {}
3934};
3935
Takashi Iwaidb064e52006-03-16 16:04:58 +01003936/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003937static struct hda_bind_ctls vaio_bind_master_vol = {
3938 .ops = &snd_hda_bind_vol,
3939 .values = {
3940 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3941 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3942 0
3943 },
3944};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003945
3946/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003947static struct hda_bind_ctls vaio_bind_master_sw = {
3948 .ops = &snd_hda_bind_sw,
3949 .values = {
3950 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3951 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3952 0,
3953 },
3954};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003955
3956static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003957 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3958 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003959 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3960 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3961 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3962 {
3963 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3964 .name = "Capture Source",
3965 .count = 1,
3966 .info = stac92xx_mux_enum_info,
3967 .get = stac92xx_mux_enum_get,
3968 .put = stac92xx_mux_enum_put,
3969 },
3970 {}
3971};
3972
Guillaume Munch6d859062006-08-22 17:15:47 +02003973static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003974 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3975 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003976 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3977 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3978 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3979 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3980 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3981 {
3982 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3983 .name = "Capture Source",
3984 .count = 1,
3985 .info = stac92xx_mux_enum_info,
3986 .get = stac92xx_mux_enum_get,
3987 .put = stac92xx_mux_enum_put,
3988 },
3989 {}
3990};
3991
3992static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003993 .build_controls = stac92xx_build_controls,
3994 .build_pcms = stac92xx_build_pcms,
3995 .init = stac92xx_init,
3996 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003997#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003998 .resume = stac92xx_resume,
3999#endif
4000};
4001
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004002static int stac9872_vaio_init(struct hda_codec *codec)
4003{
4004 int err;
4005
4006 err = stac92xx_init(codec);
4007 if (err < 0)
4008 return err;
4009 if (codec->patch_ops.unsol_event)
4010 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4011 return 0;
4012}
4013
4014static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4015{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004016 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004017 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4018 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4019 } else {
4020 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4021 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4022 }
4023}
4024
4025static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4026{
4027 switch (res >> 26) {
4028 case STAC_HP_EVENT:
4029 stac9872_vaio_hp_detect(codec, res);
4030 break;
4031 }
4032}
4033
4034static struct hda_codec_ops stac9872_vaio_patch_ops = {
4035 .build_controls = stac92xx_build_controls,
4036 .build_pcms = stac92xx_build_pcms,
4037 .init = stac9872_vaio_init,
4038 .free = stac92xx_free,
4039 .unsol_event = stac9872_vaio_unsol_event,
4040#ifdef CONFIG_PM
4041 .resume = stac92xx_resume,
4042#endif
4043};
4044
Guillaume Munch6d859062006-08-22 17:15:47 +02004045enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4046 CXD9872RD_VAIO,
4047 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4048 STAC9872AK_VAIO,
4049 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4050 STAC9872K_VAIO,
4051 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004052 CXD9872AKD_VAIO,
4053 STAC_9872_MODELS,
4054};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004055
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004056static const char *stac9872_models[STAC_9872_MODELS] = {
4057 [CXD9872RD_VAIO] = "vaio",
4058 [CXD9872AKD_VAIO] = "vaio-ar",
4059};
4060
4061static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4062 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4063 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4064 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004065 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004066 {}
4067};
4068
Guillaume Munch6d859062006-08-22 17:15:47 +02004069static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004070{
4071 struct sigmatel_spec *spec;
4072 int board_config;
4073
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004074 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4075 stac9872_models,
4076 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004077 if (board_config < 0)
4078 /* unknown config, let generic-parser do its job... */
4079 return snd_hda_parse_generic_codec(codec);
4080
4081 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4082 if (spec == NULL)
4083 return -ENOMEM;
4084
4085 codec->spec = spec;
4086 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004087 case CXD9872RD_VAIO:
4088 case STAC9872AK_VAIO:
4089 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004090 spec->mixer = vaio_mixer;
4091 spec->init = vaio_init;
4092 spec->multiout.max_channels = 2;
4093 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4094 spec->multiout.dac_nids = vaio_dacs;
4095 spec->multiout.hp_nid = VAIO_HP_DAC;
4096 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4097 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004098 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004099 spec->input_mux = &vaio_mux;
4100 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004101 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004102 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004103
4104 case CXD9872AKD_VAIO:
4105 spec->mixer = vaio_ar_mixer;
4106 spec->init = vaio_ar_init;
4107 spec->multiout.max_channels = 2;
4108 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4109 spec->multiout.dac_nids = vaio_dacs;
4110 spec->multiout.hp_nid = VAIO_HP_DAC;
4111 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004112 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004113 spec->adc_nids = vaio_adcs;
4114 spec->input_mux = &vaio_mux;
4115 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004116 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004117 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004118 }
4119
Takashi Iwaidb064e52006-03-16 16:04:58 +01004120 return 0;
4121}
4122
4123
4124/*
Matt2f2f4252005-04-13 14:45:30 +02004125 * patch entries
4126 */
4127struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4128 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4129 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4130 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4131 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4132 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4133 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4134 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004135 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4136 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4137 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4138 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4139 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4140 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004141 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4142 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4143 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4144 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4145 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4146 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4147 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4148 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4149 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4150 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004151 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4152 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4153 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4154 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4155 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4156 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004157 /* The following does not take into account .id=0x83847661 when subsys =
4158 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4159 * currently not fully supported.
4160 */
4161 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4162 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4163 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004164 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4165 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4166 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4167 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4168 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4169 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4170 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4171 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004172 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4173 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004174 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004175 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4176 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4177 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4178 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4179 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4180 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4181 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4182 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4183 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004184 {} /* terminator */
4185};