blob: 8ff7b95c34e5a66b53f690db6b293f5e7350a8ad [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010035#include "hda_patch.h"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020036#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020037
Matt4e550962005-07-04 17:51:39 +020038#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010039#define STAC_PWR_EVENT 0x20
40#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020041
Takashi Iwaif5fcc132006-11-24 17:07:44 +010042enum {
43 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010044 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020045 STAC_9200_DELL_D21,
46 STAC_9200_DELL_D22,
47 STAC_9200_DELL_D23,
48 STAC_9200_DELL_M21,
49 STAC_9200_DELL_M22,
50 STAC_9200_DELL_M23,
51 STAC_9200_DELL_M24,
52 STAC_9200_DELL_M25,
53 STAC_9200_DELL_M26,
54 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020055 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010056 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010057 STAC_9200_MODELS
58};
59
60enum {
61 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020062 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020063 STAC_9205_DELL_M43,
64 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010065 STAC_9205_MODELS
66};
67
68enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010069 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010070 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010071 STAC_92HD73XX_MODELS
72};
73
74enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020075 STAC_92HD83XXX_REF,
76 STAC_92HD83XXX_MODELS
77};
78
79enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010080 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010081 STAC_DELL_M4_1,
82 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010083 STAC_92HD71BXX_MODELS
84};
85
86enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010087 STAC_925x_REF,
88 STAC_M2_2,
89 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020090 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010091 STAC_925x_MODELS
92};
93
94enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010095 STAC_D945_REF,
96 STAC_D945GTP3,
97 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020098 STAC_INTEL_MAC_V1,
99 STAC_INTEL_MAC_V2,
100 STAC_INTEL_MAC_V3,
101 STAC_INTEL_MAC_V4,
102 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800103 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
104 * is given, one of the above models will be
105 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200106 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100107 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100108 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100109 STAC_MACBOOK_PRO_V1,
110 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200111 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200112 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300113 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200114 STAC_922X_DELL_D81,
115 STAC_922X_DELL_D82,
116 STAC_922X_DELL_M81,
117 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100118 STAC_922X_MODELS
119};
120
121enum {
122 STAC_D965_REF,
123 STAC_D965_3ST,
124 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200125 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100126 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100127 STAC_927X_MODELS
128};
Matt Porter403d1942005-11-29 15:00:51 +0100129
Matt2f2f4252005-04-13 14:45:30 +0200130struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100131 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200132 unsigned int num_mixers;
133
Matt Porter403d1942005-11-29 15:00:51 +0100134 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200135 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100136 unsigned int line_switch: 1;
137 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100138 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100139 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200140
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100141 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200142 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100143 unsigned int gpio_mask;
144 unsigned int gpio_dir;
145 unsigned int gpio_data;
146 unsigned int gpio_mute;
147
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200148 /* stream */
149 unsigned int stream_delay;
150
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100151 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100152 unsigned char aloopback_mask;
153 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200154
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100155 /* power management */
156 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200157 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100158 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100159 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100160
Matt2f2f4252005-04-13 14:45:30 +0200161 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100162 struct hda_input_mux *mono_mux;
163 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200164 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100165 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200166
167 /* capture */
168 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200169 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200170 hda_nid_t *mux_nids;
171 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200172 hda_nid_t *dmic_nids;
173 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100174 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100175 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200176 hda_nid_t *smux_nids;
177 unsigned int num_smuxes;
178
Mattdabbed62005-06-14 10:19:34 +0200179 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100180 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200181 hda_nid_t anabeep_nid;
182 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200183
Matt2f2f4252005-04-13 14:45:30 +0200184 /* pin widgets */
185 hda_nid_t *pin_nids;
186 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200187 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200188 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200189
190 /* codec specific stuff */
191 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100192 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200193
194 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200195 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100196 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200197 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100198 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200199 struct hda_input_mux *sinput_mux;
200 unsigned int cur_smux[2];
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200201 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200202
Matt Porter403d1942005-11-29 15:00:51 +0100203 /* i/o switches */
204 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200205 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200206 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200207 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200208
Mattc7d4b2f2005-06-27 14:59:41 +0200209 struct hda_pcm pcm_rec[2]; /* PCM information */
210
211 /* dynamic controls and input_mux */
212 struct auto_pin_cfg autocfg;
213 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100214 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200215 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200216 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200217 struct hda_input_mux private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100218 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200219};
220
221static hda_nid_t stac9200_adc_nids[1] = {
222 0x03,
223};
224
225static hda_nid_t stac9200_mux_nids[1] = {
226 0x0c,
227};
228
229static hda_nid_t stac9200_dac_nids[1] = {
230 0x02,
231};
232
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100233static hda_nid_t stac92hd73xx_pwr_nids[8] = {
234 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
235 0x0f, 0x10, 0x11
236};
237
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100238static hda_nid_t stac92hd73xx_adc_nids[2] = {
239 0x1a, 0x1b
240};
241
242#define STAC92HD73XX_NUM_DMICS 2
243static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
244 0x13, 0x14, 0
245};
246
247#define STAC92HD73_DAC_COUNT 5
248static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
249 0x15, 0x16, 0x17, 0x18, 0x19,
250};
251
252static hda_nid_t stac92hd73xx_mux_nids[4] = {
253 0x28, 0x29, 0x2a, 0x2b,
254};
255
256static hda_nid_t stac92hd73xx_dmux_nids[2] = {
257 0x20, 0x21,
258};
259
Matthew Ranostayd9737752008-09-07 12:03:41 +0200260static hda_nid_t stac92hd73xx_smux_nids[2] = {
261 0x22, 0x23,
262};
263
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200264#define STAC92HD83XXX_NUM_DMICS 2
265static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
266 0x11, 0x12, 0
267};
268
269#define STAC92HD81_DAC_COUNT 2
270#define STAC92HD83_DAC_COUNT 3
271static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
272 0x13, 0x14, 0x22,
273};
274
275static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
276 0x17, 0x18,
277};
278
279static hda_nid_t stac92hd83xxx_adc_nids[2] = {
280 0x15, 0x16,
281};
282
283static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
284 0xa, 0xb, 0xd, 0xe,
285};
286
287static unsigned int stac92hd83xxx_pwr_mapping[4] = {
288 0x03, 0x0c, 0x10, 0x40,
289};
290
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100291static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
292 0x0a, 0x0d, 0x0f
293};
294
Matthew Ranostaye035b842007-11-06 11:53:55 +0100295static hda_nid_t stac92hd71bxx_adc_nids[2] = {
296 0x12, 0x13,
297};
298
299static hda_nid_t stac92hd71bxx_mux_nids[2] = {
300 0x1a, 0x1b
301};
302
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100303static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
304 0x1c,
305};
306
Matthew Ranostayd9737752008-09-07 12:03:41 +0200307static hda_nid_t stac92hd71bxx_smux_nids[2] = {
308 0x24, 0x25,
309};
310
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100311static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100312 0x10, /*0x11, */
313};
314
315#define STAC92HD71BXX_NUM_DMICS 2
316static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
317 0x18, 0x19, 0
318};
319
Tobin Davis8e21c342007-01-08 11:04:17 +0100320static hda_nid_t stac925x_adc_nids[1] = {
321 0x03,
322};
323
324static hda_nid_t stac925x_mux_nids[1] = {
325 0x0f,
326};
327
328static hda_nid_t stac925x_dac_nids[1] = {
329 0x02,
330};
331
Takashi Iwaif6e98522007-10-16 14:27:04 +0200332#define STAC925X_NUM_DMICS 1
333static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
334 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200335};
336
Takashi Iwai1697055e2007-12-18 18:05:52 +0100337static hda_nid_t stac925x_dmux_nids[1] = {
338 0x14,
339};
340
Matt2f2f4252005-04-13 14:45:30 +0200341static hda_nid_t stac922x_adc_nids[2] = {
342 0x06, 0x07,
343};
344
345static hda_nid_t stac922x_mux_nids[2] = {
346 0x12, 0x13,
347};
348
Matt Porter3cc08dc2006-01-23 15:27:49 +0100349static hda_nid_t stac927x_adc_nids[3] = {
350 0x07, 0x08, 0x09
351};
352
353static hda_nid_t stac927x_mux_nids[3] = {
354 0x15, 0x16, 0x17
355};
356
Matthew Ranostayd9737752008-09-07 12:03:41 +0200357static hda_nid_t stac927x_smux_nids[1] = {
358 0x21,
359};
360
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100361static hda_nid_t stac927x_dac_nids[6] = {
362 0x02, 0x03, 0x04, 0x05, 0x06, 0
363};
364
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100365static hda_nid_t stac927x_dmux_nids[1] = {
366 0x1b,
367};
368
Matthew Ranostay7f168592007-10-18 17:38:17 +0200369#define STAC927X_NUM_DMICS 2
370static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
371 0x13, 0x14, 0
372};
373
Matt Porterf3302a52006-07-31 12:49:34 +0200374static hda_nid_t stac9205_adc_nids[2] = {
375 0x12, 0x13
376};
377
378static hda_nid_t stac9205_mux_nids[2] = {
379 0x19, 0x1a
380};
381
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100382static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100383 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100384};
385
Matthew Ranostayd9737752008-09-07 12:03:41 +0200386static hda_nid_t stac9205_smux_nids[1] = {
387 0x21,
388};
389
Takashi Iwaif6e98522007-10-16 14:27:04 +0200390#define STAC9205_NUM_DMICS 2
391static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
392 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200393};
394
Mattc7d4b2f2005-06-27 14:59:41 +0200395static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200396 0x08, 0x09, 0x0d, 0x0e,
397 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200398};
399
Tobin Davis8e21c342007-01-08 11:04:17 +0100400static hda_nid_t stac925x_pin_nids[8] = {
401 0x07, 0x08, 0x0a, 0x0b,
402 0x0c, 0x0d, 0x10, 0x11,
403};
404
Matt2f2f4252005-04-13 14:45:30 +0200405static hda_nid_t stac922x_pin_nids[10] = {
406 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
407 0x0f, 0x10, 0x11, 0x15, 0x1b,
408};
409
Matthew Ranostaya7662642008-02-21 07:51:14 +0100410static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100411 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
412 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200413 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100414};
415
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200416static hda_nid_t stac92hd83xxx_pin_nids[14] = {
417 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
418 0x0f, 0x10, 0x11, 0x12, 0x13,
419 0x1d, 0x1e, 0x1f, 0x20
420};
Matthew Ranostaye035b842007-11-06 11:53:55 +0100421static hda_nid_t stac92hd71bxx_pin_nids[10] = {
422 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
423 0x0f, 0x14, 0x18, 0x19, 0x1e,
424};
425
Matt Porter3cc08dc2006-01-23 15:27:49 +0100426static hda_nid_t stac927x_pin_nids[14] = {
427 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
428 0x0f, 0x10, 0x11, 0x12, 0x13,
429 0x14, 0x21, 0x22, 0x23,
430};
431
Matt Porterf3302a52006-07-31 12:49:34 +0200432static hda_nid_t stac9205_pin_nids[12] = {
433 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
434 0x0f, 0x14, 0x16, 0x17, 0x18,
435 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200436};
437
Matt Porter8b657272006-10-26 17:12:59 +0200438static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_info *uinfo)
440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
442 struct sigmatel_spec *spec = codec->spec;
443 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
444}
445
446static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
447 struct snd_ctl_elem_value *ucontrol)
448{
449 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
450 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100451 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200452
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100453 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200454 return 0;
455}
456
457static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
458 struct snd_ctl_elem_value *ucontrol)
459{
460 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
461 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100462 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200463
464 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100465 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200466}
467
Matthew Ranostayd9737752008-09-07 12:03:41 +0200468static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
469 struct snd_ctl_elem_info *uinfo)
470{
471 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
472 struct sigmatel_spec *spec = codec->spec;
473 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
474}
475
476static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
477 struct snd_ctl_elem_value *ucontrol)
478{
479 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
480 struct sigmatel_spec *spec = codec->spec;
481 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
482
483 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
484 return 0;
485}
486
487static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
488 struct snd_ctl_elem_value *ucontrol)
489{
490 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
491 struct sigmatel_spec *spec = codec->spec;
492 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
493
494 return snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
495 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
496}
497
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100498static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200499{
500 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
501 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200502 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200503}
504
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100505static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200506{
507 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
508 struct sigmatel_spec *spec = codec->spec;
509 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
510
511 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
512 return 0;
513}
514
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100515static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200516{
517 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
518 struct sigmatel_spec *spec = codec->spec;
519 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
520
Mattc7d4b2f2005-06-27 14:59:41 +0200521 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200522 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
523}
524
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100525static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_info *uinfo)
527{
528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
529 struct sigmatel_spec *spec = codec->spec;
530 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
531}
532
533static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
534 struct snd_ctl_elem_value *ucontrol)
535{
536 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
537 struct sigmatel_spec *spec = codec->spec;
538
539 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
540 return 0;
541}
542
543static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
545{
546 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
547 struct sigmatel_spec *spec = codec->spec;
548
549 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
550 spec->mono_nid, &spec->cur_mmux);
551}
552
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200553#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
554
555static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
556 struct snd_ctl_elem_value *ucontrol)
557{
558 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100559 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200560 struct sigmatel_spec *spec = codec->spec;
561
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100562 ucontrol->value.integer.value[0] = !!(spec->aloopback &
563 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200564 return 0;
565}
566
567static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
568 struct snd_ctl_elem_value *ucontrol)
569{
570 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
571 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100572 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200573 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100574 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200575
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100576 idx_val = spec->aloopback_mask << idx;
577 if (ucontrol->value.integer.value[0])
578 val = spec->aloopback | idx_val;
579 else
580 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100581 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200582 return 0;
583
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100584 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200585
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100586 /* Only return the bits defined by the shift value of the
587 * first two bytes of the mask
588 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200589 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100590 kcontrol->private_value & 0xFFFF, 0x0);
591 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200592
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100593 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200594 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100595 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200596 } else {
597 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100598 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200599 }
600
601 snd_hda_codec_write_cache(codec, codec->afg, 0,
602 kcontrol->private_value >> 16, dac_mode);
603
604 return 1;
605}
606
Mattc7d4b2f2005-06-27 14:59:41 +0200607static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200608 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200609 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200610 {}
611};
612
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200613static struct hda_verb stac9200_eapd_init[] = {
614 /* set dac0mux for dac converter */
615 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
616 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
617 {}
618};
619
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100620static struct hda_verb stac92hd73xx_6ch_core_init[] = {
621 /* set master volume and direct control */
622 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
623 /* setup audio connections */
624 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
625 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
626 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
627 /* setup adcs to point to mixer */
628 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
629 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100630 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
631 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
632 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
633 /* setup import muxs */
634 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
635 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
636 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
637 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
638 {}
639};
640
Matthew Ranostayd654a662008-03-14 08:46:51 +0100641static struct hda_verb dell_eq_core_init[] = {
642 /* set master volume to max value without distortion
643 * and direct control */
644 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
645 /* setup audio connections */
646 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
647 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
648 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
649 /* setup adcs to point to mixer */
650 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
651 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
652 /* setup import muxs */
653 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
654 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
655 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
656 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
657 {}
658};
659
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100660static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay20f5f952008-09-01 08:17:56 +0200661 /* set master volume to max value without distortion
662 * and direct control */
663 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100664 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100665 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
666 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100667 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
668 /* setup adcs to point to mixer */
669 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
670 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
671 /* setup import muxs */
672 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
673 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
674 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
675 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
676 {}
677};
678
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100679static struct hda_verb stac92hd73xx_8ch_core_init[] = {
680 /* set master volume and direct control */
681 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
682 /* setup audio connections */
683 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
684 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
685 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
686 /* connect hp ports to dac3 */
687 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
688 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
689 /* setup adcs to point to mixer */
690 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
691 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
693 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
694 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
695 /* setup import muxs */
696 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
697 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
698 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
699 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
700 {}
701};
702
703static struct hda_verb stac92hd73xx_10ch_core_init[] = {
704 /* set master volume and direct control */
705 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
706 /* setup audio connections */
707 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
708 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
709 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
710 /* dac3 is connected to import3 mux */
711 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
712 /* connect hp ports to dac4 */
713 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
714 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
715 /* setup adcs to point to mixer */
716 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
717 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100718 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
719 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
720 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
721 /* setup import muxs */
722 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
723 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
724 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
725 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
726 {}
727};
728
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200729static struct hda_verb stac92hd83xxx_core_init[] = {
730 /* start of config #1 */
731 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
732
733 /* start of config #2 */
734 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
735 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
736 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
737
738 /* power state controls amps */
739 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
740};
741
Matthew Ranostaye035b842007-11-06 11:53:55 +0100742static struct hda_verb stac92hd71bxx_core_init[] = {
743 /* set master volume and direct control */
744 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
745 /* connect headphone jack to dac1 */
746 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100747 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
748 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
749 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
750 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
751 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100752};
753
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200754#define HD_DISABLE_PORTF 3
Matthew Ranostay541eee82007-12-14 12:08:04 +0100755static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200756 /* start of config #1 */
757
758 /* connect port 0f to audio mixer */
759 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
760 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
761 /* unmute right and left channels for node 0x0f */
762 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
763 /* start of config #2 */
764
Matthew Ranostay541eee82007-12-14 12:08:04 +0100765 /* set master volume and direct control */
766 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
767 /* connect headphone jack to dac1 */
768 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200769 /* connect port 0d to audio mixer */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100770 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100771 /* unmute dac0 input in audio mixer */
772 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200773 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100774 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
775 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100776 {}
777};
778
Tobin Davis8e21c342007-01-08 11:04:17 +0100779static struct hda_verb stac925x_core_init[] = {
780 /* set dac0mux for dac converter */
781 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
782 {}
783};
784
Mattc7d4b2f2005-06-27 14:59:41 +0200785static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200786 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200787 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200788 {}
789};
790
Tobin Davis93ed1502006-09-01 21:03:12 +0200791static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200792 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200793 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200794 /* unmute node 0x1b */
795 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
796 /* select node 0x03 as DAC */
797 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
798 {}
799};
800
Matt Porter3cc08dc2006-01-23 15:27:49 +0100801static struct hda_verb stac927x_core_init[] = {
802 /* set master volume and direct control */
803 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200804 /* enable analog pc beep path */
805 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100806 {}
807};
808
Matt Porterf3302a52006-07-31 12:49:34 +0200809static struct hda_verb stac9205_core_init[] = {
810 /* set master volume and direct control */
811 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200812 /* enable analog pc beep path */
813 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200814 {}
815};
816
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100817#define STAC_MONO_MUX \
818 { \
819 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
820 .name = "Mono Mux", \
821 .count = 1, \
822 .info = stac92xx_mono_mux_enum_info, \
823 .get = stac92xx_mono_mux_enum_get, \
824 .put = stac92xx_mono_mux_enum_put, \
825 }
826
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200827#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200828 { \
829 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
830 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200831 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200832 .info = stac92xx_mux_enum_info, \
833 .get = stac92xx_mux_enum_get, \
834 .put = stac92xx_mux_enum_put, \
835 }
836
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100837#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200838 { \
839 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
840 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100841 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200842 .info = stac92xx_aloopback_info, \
843 .get = stac92xx_aloopback_get, \
844 .put = stac92xx_aloopback_put, \
845 .private_value = verb_read | (verb_write << 16), \
846 }
847
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100848static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200849 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
850 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200851 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200852 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
853 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200854 { } /* end */
855};
856
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100857static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100858 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
859
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100860 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
861 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
862
863 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
864 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
865
866 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
867 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
868
869 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
870 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
871
872 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
873 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
874
875 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
876 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
877
878 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
879 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
880 { } /* end */
881};
882
883static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100884 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
885
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100886 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
887 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
888
889 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
890 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
891
892 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
893 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
894
895 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
896 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
897
898 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
899 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
900
901 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
902 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
903
904 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
905 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
906 { } /* end */
907};
908
909static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100910 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
911
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100912 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
913 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
914
915 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
916 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
917
918 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
919 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
920
921 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
922 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
923
924 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
925 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
926
927 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
928 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
929
930 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
931 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
932 { } /* end */
933};
934
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200935
936static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
937 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
938 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
939
940 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
941 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
942
943 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
944 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
945
946 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
947 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
948
949 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
950 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
951
952 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
953 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
954
955 /*
956 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
957 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
958 */
959 { } /* end */
960};
961
Matthew Ranostay541eee82007-12-14 12:08:04 +0100962static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100963 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100964
Matthew Ranostay9b359472007-11-07 13:03:12 +0100965 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
966 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +0100967
968 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
969 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200970 /* analog pc-beep replaced with digital beep support */
971 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200972 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
973 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200974 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200975
Matthew Ranostay9b359472007-11-07 13:03:12 +0100976 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
977 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100978 { } /* end */
979};
980
Matthew Ranostay541eee82007-12-14 12:08:04 +0100981static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100982 STAC_INPUT_SOURCE(2),
983 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
984
Matthew Ranostay541eee82007-12-14 12:08:04 +0100985 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
986 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +0100987
988 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
989 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +0100990 { } /* end */
991};
992
Tobin Davis8e21c342007-01-08 11:04:17 +0100993static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200994 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100995 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +0200996 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +0100997 { } /* end */
998};
999
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001000static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001001 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001002 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001003
1004 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1005 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001006
1007 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1008 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001009 { } /* end */
1010};
1011
1012/* This needs to be generated dynamically based on sequence */
1013static struct snd_kcontrol_new stac922x_mixer[] = {
1014 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001015 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1016 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001017
1018 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1019 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001020 { } /* end */
1021};
1022
1023
1024static struct snd_kcontrol_new stac927x_mixer[] = {
1025 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001026 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001027
1028 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1029 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001030
1031 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1032 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001033
1034 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1035 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001036 { } /* end */
1037};
1038
Takashi Iwai1697055e2007-12-18 18:05:52 +01001039static struct snd_kcontrol_new stac_dmux_mixer = {
1040 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1041 .name = "Digital Input Source",
1042 /* count set later */
1043 .info = stac92xx_dmux_enum_info,
1044 .get = stac92xx_dmux_enum_get,
1045 .put = stac92xx_dmux_enum_put,
1046};
1047
Matthew Ranostayd9737752008-09-07 12:03:41 +02001048static struct snd_kcontrol_new stac_smux_mixer = {
1049 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1050 .name = "IEC958 Mux",
1051 /* count set later */
1052 .info = stac92xx_smux_enum_info,
1053 .get = stac92xx_smux_enum_get,
1054 .put = stac92xx_smux_enum_put,
1055};
1056
Takashi Iwai2134ea42008-01-10 16:53:55 +01001057static const char *slave_vols[] = {
1058 "Front Playback Volume",
1059 "Surround Playback Volume",
1060 "Center Playback Volume",
1061 "LFE Playback Volume",
1062 "Side Playback Volume",
1063 "Headphone Playback Volume",
1064 "Headphone Playback Volume",
1065 "Speaker Playback Volume",
1066 "External Speaker Playback Volume",
1067 "Speaker2 Playback Volume",
1068 NULL
1069};
1070
1071static const char *slave_sws[] = {
1072 "Front Playback Switch",
1073 "Surround Playback Switch",
1074 "Center Playback Switch",
1075 "LFE Playback Switch",
1076 "Side Playback Switch",
1077 "Headphone Playback Switch",
1078 "Headphone Playback Switch",
1079 "Speaker Playback Switch",
1080 "External Speaker Playback Switch",
1081 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001082 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001083 NULL
1084};
1085
Matt2f2f4252005-04-13 14:45:30 +02001086static int stac92xx_build_controls(struct hda_codec *codec)
1087{
1088 struct sigmatel_spec *spec = codec->spec;
1089 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001090 int i;
Matt2f2f4252005-04-13 14:45:30 +02001091
1092 err = snd_hda_add_new_ctls(codec, spec->mixer);
1093 if (err < 0)
1094 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001095
1096 for (i = 0; i < spec->num_mixers; i++) {
1097 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1098 if (err < 0)
1099 return err;
1100 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001101 if (spec->num_dmuxes > 0) {
1102 stac_dmux_mixer.count = spec->num_dmuxes;
1103 err = snd_ctl_add(codec->bus->card,
1104 snd_ctl_new1(&stac_dmux_mixer, codec));
1105 if (err < 0)
1106 return err;
1107 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001108 if (spec->num_smuxes > 0) {
1109 stac_smux_mixer.count = spec->num_smuxes;
1110 err = snd_ctl_add(codec->bus->card,
1111 snd_ctl_new1(&stac_smux_mixer, codec));
1112 if (err < 0)
1113 return err;
1114 }
Mattc7d4b2f2005-06-27 14:59:41 +02001115
Mattdabbed62005-06-14 10:19:34 +02001116 if (spec->multiout.dig_out_nid) {
1117 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1118 if (err < 0)
1119 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001120 err = snd_hda_create_spdif_share_sw(codec,
1121 &spec->multiout);
1122 if (err < 0)
1123 return err;
1124 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001125 }
1126 if (spec->dig_in_nid) {
1127 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1128 if (err < 0)
1129 return err;
1130 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001131
1132 /* if we have no master control, let's create it */
1133 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001134 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001135 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001136 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001137 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001138 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001139 if (err < 0)
1140 return err;
1141 }
1142 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1143 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1144 NULL, slave_sws);
1145 if (err < 0)
1146 return err;
1147 }
1148
Mattdabbed62005-06-14 10:19:34 +02001149 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001150}
1151
Matt Porter403d1942005-11-29 15:00:51 +01001152static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001153 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001154 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1155};
1156
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001157/*
1158 STAC 9200 pin configs for
1159 102801A8
1160 102801DE
1161 102801E8
1162*/
1163static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001164 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1165 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001166};
1167
1168/*
1169 STAC 9200 pin configs for
1170 102801C0
1171 102801C1
1172*/
1173static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001174 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1175 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001176};
1177
1178/*
1179 STAC 9200 pin configs for
1180 102801C4 (Dell Dimension E310)
1181 102801C5
1182 102801C7
1183 102801D9
1184 102801DA
1185 102801E3
1186*/
1187static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001188 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1189 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001190};
1191
1192
1193/*
1194 STAC 9200-32 pin configs for
1195 102801B5 (Dell Inspiron 630m)
1196 102801D8 (Dell Inspiron 640m)
1197*/
1198static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001199 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1200 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001201};
1202
1203/*
1204 STAC 9200-32 pin configs for
1205 102801C2 (Dell Latitude D620)
1206 102801C8
1207 102801CC (Dell Latitude D820)
1208 102801D4
1209 102801D6
1210*/
1211static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001212 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1213 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001214};
1215
1216/*
1217 STAC 9200-32 pin configs for
1218 102801CE (Dell XPS M1710)
1219 102801CF (Dell Precision M90)
1220*/
1221static unsigned int dell9200_m23_pin_configs[8] = {
1222 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1223 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1224};
1225
1226/*
1227 STAC 9200-32 pin configs for
1228 102801C9
1229 102801CA
1230 102801CB (Dell Latitude 120L)
1231 102801D3
1232*/
1233static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001234 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1235 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001236};
1237
1238/*
1239 STAC 9200-32 pin configs for
1240 102801BD (Dell Inspiron E1505n)
1241 102801EE
1242 102801EF
1243*/
1244static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001245 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1246 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001247};
1248
1249/*
1250 STAC 9200-32 pin configs for
1251 102801F5 (Dell Inspiron 1501)
1252 102801F6
1253*/
1254static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001255 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1256 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001257};
1258
1259/*
1260 STAC 9200-32
1261 102801CD (Dell Inspiron E1705/9400)
1262*/
1263static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001264 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1265 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001266};
1267
Tobin Davisbf277782008-02-03 20:31:47 +01001268static unsigned int oqo9200_pin_configs[8] = {
1269 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1270 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1271};
1272
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001273
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001274static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1275 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001276 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001277 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1278 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1279 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1280 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1281 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1282 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1283 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1284 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1285 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1286 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001287 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001288};
1289
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001290static const char *stac9200_models[STAC_9200_MODELS] = {
1291 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001292 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001293 [STAC_9200_DELL_D21] = "dell-d21",
1294 [STAC_9200_DELL_D22] = "dell-d22",
1295 [STAC_9200_DELL_D23] = "dell-d23",
1296 [STAC_9200_DELL_M21] = "dell-m21",
1297 [STAC_9200_DELL_M22] = "dell-m22",
1298 [STAC_9200_DELL_M23] = "dell-m23",
1299 [STAC_9200_DELL_M24] = "dell-m24",
1300 [STAC_9200_DELL_M25] = "dell-m25",
1301 [STAC_9200_DELL_M26] = "dell-m26",
1302 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001303 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001304 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001305};
1306
1307static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1308 /* SigmaTel reference board */
1309 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1310 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001311 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001312 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1313 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001314 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001315 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1316 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1317 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1318 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1319 "unknown Dell", STAC_9200_DELL_D22),
1320 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1321 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001322 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001323 "Dell Latitude D620", STAC_9200_DELL_M22),
1324 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1325 "unknown Dell", STAC_9200_DELL_D23),
1326 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1327 "unknown Dell", STAC_9200_DELL_D23),
1328 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1329 "unknown Dell", STAC_9200_DELL_M22),
1330 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1331 "unknown Dell", STAC_9200_DELL_M24),
1332 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1333 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001334 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001335 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001336 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001337 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001338 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001339 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001340 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001341 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001342 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001343 "Dell Precision M90", STAC_9200_DELL_M23),
1344 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1345 "unknown Dell", STAC_9200_DELL_M22),
1346 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1347 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001348 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001349 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001350 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001351 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1352 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1353 "unknown Dell", STAC_9200_DELL_D23),
1354 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1355 "unknown Dell", STAC_9200_DELL_D23),
1356 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1357 "unknown Dell", STAC_9200_DELL_D21),
1358 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1359 "unknown Dell", STAC_9200_DELL_D23),
1360 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1361 "unknown Dell", STAC_9200_DELL_D21),
1362 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1363 "unknown Dell", STAC_9200_DELL_M25),
1364 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1365 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001366 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001367 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1368 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1369 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001370 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001371 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001372 /* Gateway machines needs EAPD to be set on resume */
1373 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1374 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1375 STAC_9200_GATEWAY),
1376 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1377 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001378 /* OQO Mobile */
1379 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001380 {} /* terminator */
1381};
1382
Tobin Davis8e21c342007-01-08 11:04:17 +01001383static unsigned int ref925x_pin_configs[8] = {
1384 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001385 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001386};
1387
1388static unsigned int stac925x_MA6_pin_configs[8] = {
1389 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1390 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1391};
1392
Tobin Davis2c11f952007-05-17 09:36:34 +02001393static unsigned int stac925x_PA6_pin_configs[8] = {
1394 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1395 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1396};
1397
Tobin Davis8e21c342007-01-08 11:04:17 +01001398static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001399 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1400 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001401};
1402
1403static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1404 [STAC_REF] = ref925x_pin_configs,
1405 [STAC_M2_2] = stac925xM2_2_pin_configs,
1406 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001407 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001408};
1409
1410static const char *stac925x_models[STAC_925x_MODELS] = {
1411 [STAC_REF] = "ref",
1412 [STAC_M2_2] = "m2-2",
1413 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001414 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001415};
1416
1417static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1418 /* SigmaTel reference board */
1419 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001420 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001421 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1422 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1423 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001424 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001425 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1426 {} /* terminator */
1427};
1428
Matthew Ranostaya7662642008-02-21 07:51:14 +01001429static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001430 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1431 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1432 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001433 0x01452050,
1434};
1435
1436static unsigned int dell_m6_pin_configs[13] = {
1437 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001438 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001439 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1440 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001441};
1442
1443static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001444 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1445 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001446};
1447
1448static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1449 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001450 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001451};
1452
1453static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1454 /* SigmaTel reference board */
1455 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001456 "DFI LanParty", STAC_92HD73XX_REF),
1457 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1458 "unknown Dell", STAC_DELL_M6),
1459 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1460 "unknown Dell", STAC_DELL_M6),
1461 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1462 "unknown Dell", STAC_DELL_M6),
1463 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1464 "unknown Dell", STAC_DELL_M6),
1465 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1466 "unknown Dell", STAC_DELL_M6),
1467 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1468 "unknown Dell", STAC_DELL_M6),
1469 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1470 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001471 {} /* terminator */
1472};
1473
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001474static unsigned int ref92hd83xxx_pin_configs[14] = {
1475 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1476 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1477 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1478 0x01451160, 0x98560170,
1479};
1480
1481static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1482 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1483};
1484
1485static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1486 [STAC_92HD83XXX_REF] = "ref",
1487};
1488
1489static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1490 /* SigmaTel reference board */
1491 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1492 "DFI LanParty", STAC_92HD71BXX_REF),
1493};
1494
Matthew Ranostaye035b842007-11-06 11:53:55 +01001495static unsigned int ref92hd71bxx_pin_configs[10] = {
1496 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001497 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001498 0x90a000f0, 0x01452050,
1499};
1500
Matthew Ranostayaafc4412008-06-13 18:04:33 +02001501static unsigned int dell_m4_1_pin_configs[10] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001502 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001503 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001504 0x40f000f0, 0x4f0000f0,
1505};
1506
Matthew Ranostayaafc4412008-06-13 18:04:33 +02001507static unsigned int dell_m4_2_pin_configs[10] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001508 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1509 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1510 0x40f000f0, 0x044413b0,
1511};
1512
Matthew Ranostaye035b842007-11-06 11:53:55 +01001513static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1514 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001515 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1516 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001517};
1518
1519static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1520 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001521 [STAC_DELL_M4_1] = "dell-m4-1",
1522 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001523};
1524
1525static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1526 /* SigmaTel reference board */
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1528 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001529 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1530 "unknown Dell", STAC_DELL_M4_1),
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1532 "unknown Dell", STAC_DELL_M4_1),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1534 "unknown Dell", STAC_DELL_M4_1),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1536 "unknown Dell", STAC_DELL_M4_1),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1538 "unknown Dell", STAC_DELL_M4_1),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1540 "unknown Dell", STAC_DELL_M4_1),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1542 "unknown Dell", STAC_DELL_M4_1),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1544 "unknown Dell", STAC_DELL_M4_2),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1546 "unknown Dell", STAC_DELL_M4_2),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1548 "unknown Dell", STAC_DELL_M4_2),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1550 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001551 {} /* terminator */
1552};
1553
Matt Porter403d1942005-11-29 15:00:51 +01001554static unsigned int ref922x_pin_configs[10] = {
1555 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1556 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001557 0x40000100, 0x40000100,
1558};
1559
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001560/*
1561 STAC 922X pin configs for
1562 102801A7
1563 102801AB
1564 102801A9
1565 102801D1
1566 102801D2
1567*/
1568static unsigned int dell_922x_d81_pin_configs[10] = {
1569 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1570 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1571 0x01813122, 0x400001f2,
1572};
1573
1574/*
1575 STAC 922X pin configs for
1576 102801AC
1577 102801D0
1578*/
1579static unsigned int dell_922x_d82_pin_configs[10] = {
1580 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1581 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1582 0x01813122, 0x400001f1,
1583};
1584
1585/*
1586 STAC 922X pin configs for
1587 102801BF
1588*/
1589static unsigned int dell_922x_m81_pin_configs[10] = {
1590 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1591 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1592 0x40C003f1, 0x405003f0,
1593};
1594
1595/*
1596 STAC 9221 A1 pin configs for
1597 102801D7 (Dell XPS M1210)
1598*/
1599static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001600 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1601 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001602 0x508003f3, 0x405003f4,
1603};
1604
Matt Porter403d1942005-11-29 15:00:51 +01001605static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001606 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001607 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1608 0x02a19120, 0x40000100,
1609};
1610
1611static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001612 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1613 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001614 0x02a19320, 0x40000100,
1615};
1616
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001617static unsigned int intel_mac_v1_pin_configs[10] = {
1618 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1619 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001620 0x400000fc, 0x400000fb,
1621};
1622
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001623static unsigned int intel_mac_v2_pin_configs[10] = {
1624 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1625 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001626 0x400000fc, 0x400000fb,
1627};
1628
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001629static unsigned int intel_mac_v3_pin_configs[10] = {
1630 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1631 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1632 0x400000fc, 0x400000fb,
1633};
1634
1635static unsigned int intel_mac_v4_pin_configs[10] = {
1636 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1637 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1638 0x400000fc, 0x400000fb,
1639};
1640
1641static unsigned int intel_mac_v5_pin_configs[10] = {
1642 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1643 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1644 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001645};
1646
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001647static unsigned int ecs202_pin_configs[10] = {
1648 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1649 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1650 0x9037012e, 0x40e000f2,
1651};
Takashi Iwai76c08822007-06-19 12:17:42 +02001652
Takashi Iwai19039bd2006-06-28 15:52:16 +02001653static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001654 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001655 [STAC_D945GTP3] = d945gtp3_pin_configs,
1656 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001657 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1658 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1659 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1660 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1661 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001662 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001663 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001664 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1665 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1666 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1667 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1668 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1669 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001670 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001671 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1672 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1673 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1674 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001675};
1676
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001677static const char *stac922x_models[STAC_922X_MODELS] = {
1678 [STAC_D945_REF] = "ref",
1679 [STAC_D945GTP5] = "5stack",
1680 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001681 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1682 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1683 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1684 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1685 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001686 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001687 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001688 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001689 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001690 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1691 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001692 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001693 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001694 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001695 [STAC_922X_DELL_D81] = "dell-d81",
1696 [STAC_922X_DELL_D82] = "dell-d82",
1697 [STAC_922X_DELL_M81] = "dell-m81",
1698 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001699};
1700
1701static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1702 /* SigmaTel reference board */
1703 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1704 "DFI LanParty", STAC_D945_REF),
1705 /* Intel 945G based systems */
1706 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1707 "Intel D945G", STAC_D945GTP3),
1708 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1709 "Intel D945G", STAC_D945GTP3),
1710 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1711 "Intel D945G", STAC_D945GTP3),
1712 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1713 "Intel D945G", STAC_D945GTP3),
1714 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1715 "Intel D945G", STAC_D945GTP3),
1716 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1717 "Intel D945G", STAC_D945GTP3),
1718 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1719 "Intel D945G", STAC_D945GTP3),
1720 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1721 "Intel D945G", STAC_D945GTP3),
1722 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1723 "Intel D945G", STAC_D945GTP3),
1724 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1725 "Intel D945G", STAC_D945GTP3),
1726 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1727 "Intel D945G", STAC_D945GTP3),
1728 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1729 "Intel D945G", STAC_D945GTP3),
1730 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1731 "Intel D945G", STAC_D945GTP3),
1732 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1733 "Intel D945G", STAC_D945GTP3),
1734 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1735 "Intel D945G", STAC_D945GTP3),
1736 /* Intel D945G 5-stack systems */
1737 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1738 "Intel D945G", STAC_D945GTP5),
1739 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1740 "Intel D945G", STAC_D945GTP5),
1741 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1742 "Intel D945G", STAC_D945GTP5),
1743 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1744 "Intel D945G", STAC_D945GTP5),
1745 /* Intel 945P based systems */
1746 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1747 "Intel D945P", STAC_D945GTP3),
1748 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1749 "Intel D945P", STAC_D945GTP3),
1750 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1751 "Intel D945P", STAC_D945GTP3),
1752 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1753 "Intel D945P", STAC_D945GTP3),
1754 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1755 "Intel D945P", STAC_D945GTP3),
1756 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1757 "Intel D945P", STAC_D945GTP5),
1758 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001759 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001760 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001761 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001762 /* Dell systems */
1763 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1764 "unknown Dell", STAC_922X_DELL_D81),
1765 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1766 "unknown Dell", STAC_922X_DELL_D81),
1767 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1768 "unknown Dell", STAC_922X_DELL_D81),
1769 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1770 "unknown Dell", STAC_922X_DELL_D82),
1771 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1772 "unknown Dell", STAC_922X_DELL_M81),
1773 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1774 "unknown Dell", STAC_922X_DELL_D82),
1775 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1776 "unknown Dell", STAC_922X_DELL_D81),
1777 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1778 "unknown Dell", STAC_922X_DELL_D81),
1779 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1780 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001781 /* ECS/PC Chips boards */
1782 SND_PCI_QUIRK(0x1019, 0x2144,
1783 "ECS/PC chips", STAC_ECS_202),
1784 SND_PCI_QUIRK(0x1019, 0x2608,
1785 "ECS/PC chips", STAC_ECS_202),
1786 SND_PCI_QUIRK(0x1019, 0x2633,
1787 "ECS/PC chips P17G/1333", STAC_ECS_202),
1788 SND_PCI_QUIRK(0x1019, 0x2811,
1789 "ECS/PC chips", STAC_ECS_202),
1790 SND_PCI_QUIRK(0x1019, 0x2812,
1791 "ECS/PC chips", STAC_ECS_202),
1792 SND_PCI_QUIRK(0x1019, 0x2813,
1793 "ECS/PC chips", STAC_ECS_202),
1794 SND_PCI_QUIRK(0x1019, 0x2814,
1795 "ECS/PC chips", STAC_ECS_202),
1796 SND_PCI_QUIRK(0x1019, 0x2815,
1797 "ECS/PC chips", STAC_ECS_202),
1798 SND_PCI_QUIRK(0x1019, 0x2816,
1799 "ECS/PC chips", STAC_ECS_202),
1800 SND_PCI_QUIRK(0x1019, 0x2817,
1801 "ECS/PC chips", STAC_ECS_202),
1802 SND_PCI_QUIRK(0x1019, 0x2818,
1803 "ECS/PC chips", STAC_ECS_202),
1804 SND_PCI_QUIRK(0x1019, 0x2819,
1805 "ECS/PC chips", STAC_ECS_202),
1806 SND_PCI_QUIRK(0x1019, 0x2820,
1807 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001808 {} /* terminator */
1809};
1810
Matt Porter3cc08dc2006-01-23 15:27:49 +01001811static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001812 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1813 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1814 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1815 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001816};
1817
Tobin Davis93ed1502006-09-01 21:03:12 +02001818static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001819 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1820 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1821 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1822 0x40000100, 0x40000100
1823};
1824
Tobin Davis93ed1502006-09-01 21:03:12 +02001825static unsigned int d965_5st_pin_configs[14] = {
1826 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1827 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1828 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1829 0x40000100, 0x40000100
1830};
1831
Tobin Davis4ff076e2007-08-07 11:48:12 +02001832static unsigned int dell_3st_pin_configs[14] = {
1833 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1834 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001835 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001836 0x40c003fc, 0x40000100
1837};
1838
Tobin Davis93ed1502006-09-01 21:03:12 +02001839static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001840 [STAC_D965_REF] = ref927x_pin_configs,
1841 [STAC_D965_3ST] = d965_3st_pin_configs,
1842 [STAC_D965_5ST] = d965_5st_pin_configs,
1843 [STAC_DELL_3ST] = dell_3st_pin_configs,
1844 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001845};
1846
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001847static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001848 [STAC_D965_REF] = "ref",
1849 [STAC_D965_3ST] = "3stack",
1850 [STAC_D965_5ST] = "5stack",
1851 [STAC_DELL_3ST] = "dell-3stack",
1852 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001853};
1854
1855static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1856 /* SigmaTel reference board */
1857 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1858 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001859 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001860 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1861 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001862 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001863 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1864 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1865 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1866 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1867 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1868 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1869 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1870 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1871 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1872 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1873 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1874 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1875 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1876 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1877 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1878 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001879 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001880 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001881 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001882 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1883 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001884 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001885 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1886 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001887 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02001888 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001889 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1890 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1891 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1892 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001893 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001894 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1895 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1896 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1897 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1898 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1899 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1900 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1901 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1902 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001903 {} /* terminator */
1904};
1905
Matt Porterf3302a52006-07-31 12:49:34 +02001906static unsigned int ref9205_pin_configs[12] = {
1907 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001908 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001909 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001910};
1911
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001912/*
1913 STAC 9205 pin configs for
1914 102801F1
1915 102801F2
1916 102801FC
1917 102801FD
1918 10280204
1919 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001920 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001921*/
1922static unsigned int dell_9205_m42_pin_configs[12] = {
1923 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1924 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1925 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1926};
1927
1928/*
1929 STAC 9205 pin configs for
1930 102801F9
1931 102801FA
1932 102801FE
1933 102801FF (Dell Precision M4300)
1934 10280206
1935 10280200
1936 10280201
1937*/
1938static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001939 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1940 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1941 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1942};
1943
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001944static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001945 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1946 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1947 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1948};
1949
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001950static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001951 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001952 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1953 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1954 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001955};
1956
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001957static const char *stac9205_models[STAC_9205_MODELS] = {
1958 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001959 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001960 [STAC_9205_DELL_M43] = "dell-m43",
1961 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001962};
1963
1964static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1965 /* SigmaTel reference board */
1966 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1967 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001968 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1969 "unknown Dell", STAC_9205_DELL_M42),
1970 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1971 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001972 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001973 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001974 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1975 "Dell Precision", STAC_9205_DELL_M43),
1976 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1977 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001978 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1979 "unknown Dell", STAC_9205_DELL_M42),
1980 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1981 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001982 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1983 "Dell Precision", STAC_9205_DELL_M43),
1984 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001985 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001986 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1987 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02001988 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1989 "Dell Precision", STAC_9205_DELL_M43),
1990 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1991 "Dell Precision", STAC_9205_DELL_M43),
1992 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1993 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001994 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1995 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001996 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1997 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001998 {} /* terminator */
1999};
2000
Richard Fish11b44bb2006-08-23 18:31:34 +02002001static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2002{
2003 int i;
2004 struct sigmatel_spec *spec = codec->spec;
2005
2006 if (! spec->bios_pin_configs) {
2007 spec->bios_pin_configs = kcalloc(spec->num_pins,
2008 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2009 if (! spec->bios_pin_configs)
2010 return -ENOMEM;
2011 }
2012
2013 for (i = 0; i < spec->num_pins; i++) {
2014 hda_nid_t nid = spec->pin_nids[i];
2015 unsigned int pin_cfg;
2016
2017 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2018 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2019 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2020 nid, pin_cfg);
2021 spec->bios_pin_configs[i] = pin_cfg;
2022 }
2023
2024 return 0;
2025}
2026
Matthew Ranostay87d48362007-07-17 11:52:24 +02002027static void stac92xx_set_config_reg(struct hda_codec *codec,
2028 hda_nid_t pin_nid, unsigned int pin_config)
2029{
2030 int i;
2031 snd_hda_codec_write(codec, pin_nid, 0,
2032 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2033 pin_config & 0x000000ff);
2034 snd_hda_codec_write(codec, pin_nid, 0,
2035 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2036 (pin_config & 0x0000ff00) >> 8);
2037 snd_hda_codec_write(codec, pin_nid, 0,
2038 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2039 (pin_config & 0x00ff0000) >> 16);
2040 snd_hda_codec_write(codec, pin_nid, 0,
2041 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2042 pin_config >> 24);
2043 i = snd_hda_codec_read(codec, pin_nid, 0,
2044 AC_VERB_GET_CONFIG_DEFAULT,
2045 0x00);
2046 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2047 pin_nid, i);
2048}
2049
Matt2f2f4252005-04-13 14:45:30 +02002050static void stac92xx_set_config_regs(struct hda_codec *codec)
2051{
2052 int i;
2053 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002054
Matthew Ranostay87d48362007-07-17 11:52:24 +02002055 if (!spec->pin_configs)
2056 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002057
Matthew Ranostay87d48362007-07-17 11:52:24 +02002058 for (i = 0; i < spec->num_pins; i++)
2059 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2060 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002061}
Matt2f2f4252005-04-13 14:45:30 +02002062
Matt2f2f4252005-04-13 14:45:30 +02002063/*
2064 * Analog playback callbacks
2065 */
2066static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2067 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002068 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002069{
2070 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002071 if (spec->stream_delay)
2072 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002073 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2074 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002075}
2076
2077static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2078 struct hda_codec *codec,
2079 unsigned int stream_tag,
2080 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002081 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002082{
2083 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002084 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002085}
2086
2087static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2088 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002089 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002090{
2091 struct sigmatel_spec *spec = codec->spec;
2092 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2093}
2094
2095/*
Mattdabbed62005-06-14 10:19:34 +02002096 * Digital playback callbacks
2097 */
2098static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2099 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002100 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002101{
2102 struct sigmatel_spec *spec = codec->spec;
2103 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2104}
2105
2106static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2107 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002108 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002109{
2110 struct sigmatel_spec *spec = codec->spec;
2111 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2112}
2113
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002114static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2115 struct hda_codec *codec,
2116 unsigned int stream_tag,
2117 unsigned int format,
2118 struct snd_pcm_substream *substream)
2119{
2120 struct sigmatel_spec *spec = codec->spec;
2121 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2122 stream_tag, format, substream);
2123}
2124
Mattdabbed62005-06-14 10:19:34 +02002125
2126/*
Matt2f2f4252005-04-13 14:45:30 +02002127 * Analog capture callbacks
2128 */
2129static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2130 struct hda_codec *codec,
2131 unsigned int stream_tag,
2132 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002133 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002134{
2135 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002136 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002137
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002138 if (spec->powerdown_adcs) {
2139 msleep(40);
2140 snd_hda_codec_write_cache(codec, nid, 0,
2141 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2142 }
2143 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002144 return 0;
2145}
2146
2147static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2148 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002149 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002150{
2151 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002152 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002153
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002154 snd_hda_codec_cleanup_stream(codec, nid);
2155 if (spec->powerdown_adcs)
2156 snd_hda_codec_write_cache(codec, nid, 0,
2157 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002158 return 0;
2159}
2160
Mattdabbed62005-06-14 10:19:34 +02002161static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2162 .substreams = 1,
2163 .channels_min = 2,
2164 .channels_max = 2,
2165 /* NID is set in stac92xx_build_pcms */
2166 .ops = {
2167 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002168 .close = stac92xx_dig_playback_pcm_close,
2169 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002170 },
2171};
2172
2173static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2174 .substreams = 1,
2175 .channels_min = 2,
2176 .channels_max = 2,
2177 /* NID is set in stac92xx_build_pcms */
2178};
2179
Matt2f2f4252005-04-13 14:45:30 +02002180static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2181 .substreams = 1,
2182 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002183 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002184 .nid = 0x02, /* NID to query formats and rates */
2185 .ops = {
2186 .open = stac92xx_playback_pcm_open,
2187 .prepare = stac92xx_playback_pcm_prepare,
2188 .cleanup = stac92xx_playback_pcm_cleanup
2189 },
2190};
2191
Matt Porter3cc08dc2006-01-23 15:27:49 +01002192static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2193 .substreams = 1,
2194 .channels_min = 2,
2195 .channels_max = 2,
2196 .nid = 0x06, /* NID to query formats and rates */
2197 .ops = {
2198 .open = stac92xx_playback_pcm_open,
2199 .prepare = stac92xx_playback_pcm_prepare,
2200 .cleanup = stac92xx_playback_pcm_cleanup
2201 },
2202};
2203
Matt2f2f4252005-04-13 14:45:30 +02002204static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002205 .channels_min = 2,
2206 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002207 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002208 .ops = {
2209 .prepare = stac92xx_capture_pcm_prepare,
2210 .cleanup = stac92xx_capture_pcm_cleanup
2211 },
2212};
2213
2214static int stac92xx_build_pcms(struct hda_codec *codec)
2215{
2216 struct sigmatel_spec *spec = codec->spec;
2217 struct hda_pcm *info = spec->pcm_rec;
2218
2219 codec->num_pcms = 1;
2220 codec->pcm_info = info;
2221
Mattc7d4b2f2005-06-27 14:59:41 +02002222 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002223 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002224 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002225 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002226 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002227
2228 if (spec->alt_switch) {
2229 codec->num_pcms++;
2230 info++;
2231 info->name = "STAC92xx Analog Alt";
2232 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2233 }
Matt2f2f4252005-04-13 14:45:30 +02002234
Mattdabbed62005-06-14 10:19:34 +02002235 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2236 codec->num_pcms++;
2237 info++;
2238 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002239 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002240 if (spec->multiout.dig_out_nid) {
2241 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2242 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2243 }
2244 if (spec->dig_in_nid) {
2245 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2246 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2247 }
2248 }
2249
Matt2f2f4252005-04-13 14:45:30 +02002250 return 0;
2251}
2252
Takashi Iwaic960a032006-03-23 17:06:28 +01002253static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2254{
2255 unsigned int pincap = snd_hda_param_read(codec, nid,
2256 AC_PAR_PIN_CAP);
2257 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2258 if (pincap & AC_PINCAP_VREF_100)
2259 return AC_PINCTL_VREF_100;
2260 if (pincap & AC_PINCAP_VREF_80)
2261 return AC_PINCTL_VREF_80;
2262 if (pincap & AC_PINCAP_VREF_50)
2263 return AC_PINCTL_VREF_50;
2264 if (pincap & AC_PINCAP_VREF_GRD)
2265 return AC_PINCTL_VREF_GRD;
2266 return 0;
2267}
2268
Matt Porter403d1942005-11-29 15:00:51 +01002269static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2270
2271{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002272 snd_hda_codec_write_cache(codec, nid, 0,
2273 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002274}
2275
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002276#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2277
2278static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2279 struct snd_ctl_elem_value *ucontrol)
2280{
2281 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2282 struct sigmatel_spec *spec = codec->spec;
2283
2284 ucontrol->value.integer.value[0] = spec->hp_switch;
2285 return 0;
2286}
2287
2288static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2289 struct snd_ctl_elem_value *ucontrol)
2290{
2291 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2292 struct sigmatel_spec *spec = codec->spec;
2293
2294 spec->hp_switch = ucontrol->value.integer.value[0];
2295
2296 /* check to be sure that the ports are upto date with
2297 * switch changes
2298 */
2299 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2300
2301 return 1;
2302}
2303
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002304#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002305
2306static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2307{
2308 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2309 struct sigmatel_spec *spec = codec->spec;
2310 int io_idx = kcontrol-> private_value & 0xff;
2311
2312 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2313 return 0;
2314}
2315
2316static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2317{
2318 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2319 struct sigmatel_spec *spec = codec->spec;
2320 hda_nid_t nid = kcontrol->private_value >> 8;
2321 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002322 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002323
2324 spec->io_switch[io_idx] = val;
2325
2326 if (val)
2327 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002328 else {
2329 unsigned int pinctl = AC_PINCTL_IN_EN;
2330 if (io_idx) /* set VREF for mic */
2331 pinctl |= stac92xx_get_vref(codec, nid);
2332 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2333 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002334
2335 /* check the auto-mute again: we need to mute/unmute the speaker
2336 * appropriately according to the pin direction
2337 */
2338 if (spec->hp_detect)
2339 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2340
Matt Porter403d1942005-11-29 15:00:51 +01002341 return 1;
2342}
2343
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002344#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2345
2346static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2347 struct snd_ctl_elem_value *ucontrol)
2348{
2349 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2350 struct sigmatel_spec *spec = codec->spec;
2351
2352 ucontrol->value.integer.value[0] = spec->clfe_swap;
2353 return 0;
2354}
2355
2356static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2357 struct snd_ctl_elem_value *ucontrol)
2358{
2359 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2360 struct sigmatel_spec *spec = codec->spec;
2361 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002362 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002363
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002364 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002365 return 0;
2366
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002367 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002368
2369 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2370 spec->clfe_swap ? 0x4 : 0x0);
2371
2372 return 1;
2373}
2374
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002375#define STAC_CODEC_HP_SWITCH(xname) \
2376 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2377 .name = xname, \
2378 .index = 0, \
2379 .info = stac92xx_hp_switch_info, \
2380 .get = stac92xx_hp_switch_get, \
2381 .put = stac92xx_hp_switch_put, \
2382 }
2383
Matt Porter403d1942005-11-29 15:00:51 +01002384#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2385 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2386 .name = xname, \
2387 .index = 0, \
2388 .info = stac92xx_io_switch_info, \
2389 .get = stac92xx_io_switch_get, \
2390 .put = stac92xx_io_switch_put, \
2391 .private_value = xpval, \
2392 }
2393
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002394#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2395 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2396 .name = xname, \
2397 .index = 0, \
2398 .info = stac92xx_clfe_switch_info, \
2399 .get = stac92xx_clfe_switch_get, \
2400 .put = stac92xx_clfe_switch_put, \
2401 .private_value = xpval, \
2402 }
Matt Porter403d1942005-11-29 15:00:51 +01002403
Mattc7d4b2f2005-06-27 14:59:41 +02002404enum {
2405 STAC_CTL_WIDGET_VOL,
2406 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002407 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002408 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002409 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002410 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002411};
2412
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002413static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002414 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2415 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002416 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002417 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002418 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002419 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002420};
2421
2422/* add dynamic controls */
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002423static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
2424 int idx, const char *name, unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002425{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002426 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002427
2428 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2429 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2430
2431 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2432 if (! knew)
2433 return -ENOMEM;
2434 if (spec->kctl_alloc) {
2435 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2436 kfree(spec->kctl_alloc);
2437 }
2438 spec->kctl_alloc = knew;
2439 spec->num_kctl_alloc = num;
2440 }
2441
2442 knew = &spec->kctl_alloc[spec->num_kctl_used];
2443 *knew = stac92xx_control_templates[type];
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002444 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002445 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002446 if (! knew->name)
2447 return -ENOMEM;
2448 knew->private_value = val;
2449 spec->num_kctl_used++;
2450 return 0;
2451}
2452
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002453
2454/* add dynamic controls */
2455static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2456 const char *name, unsigned long val)
2457{
2458 return stac92xx_add_control_idx(spec, type, 0, name, val);
2459}
2460
Matt Porter403d1942005-11-29 15:00:51 +01002461/* flag inputs as additional dynamic lineouts */
2462static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2463{
2464 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002465 unsigned int wcaps, wtype;
2466 int i, num_dacs = 0;
2467
2468 /* use the wcaps cache to count all DACs available for line-outs */
2469 for (i = 0; i < codec->num_nodes; i++) {
2470 wcaps = codec->wcaps[i];
2471 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002472
Steve Longerbeam7b043892007-05-03 20:50:03 +02002473 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2474 num_dacs++;
2475 }
Matt Porter403d1942005-11-29 15:00:51 +01002476
Steve Longerbeam7b043892007-05-03 20:50:03 +02002477 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2478
Matt Porter403d1942005-11-29 15:00:51 +01002479 switch (cfg->line_outs) {
2480 case 3:
2481 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002482 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002483 cfg->line_out_pins[cfg->line_outs] =
2484 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002485 spec->line_switch = 1;
2486 cfg->line_outs++;
2487 }
2488 break;
2489 case 2:
2490 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002491 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002492 cfg->line_out_pins[cfg->line_outs] =
2493 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002494 spec->line_switch = 1;
2495 cfg->line_outs++;
2496 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002497 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002498 cfg->line_out_pins[cfg->line_outs] =
2499 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002500 spec->mic_switch = 1;
2501 cfg->line_outs++;
2502 }
2503 break;
2504 case 1:
2505 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002506 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002507 cfg->line_out_pins[cfg->line_outs] =
2508 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002509 spec->line_switch = 1;
2510 cfg->line_outs++;
2511 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002512 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002513 cfg->line_out_pins[cfg->line_outs] =
2514 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002515 spec->mic_switch = 1;
2516 cfg->line_outs++;
2517 }
2518 break;
2519 }
2520
2521 return 0;
2522}
2523
Steve Longerbeam7b043892007-05-03 20:50:03 +02002524
2525static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2526{
2527 int i;
2528
2529 for (i = 0; i < spec->multiout.num_dacs; i++) {
2530 if (spec->multiout.dac_nids[i] == nid)
2531 return 1;
2532 }
2533
2534 return 0;
2535}
2536
Matt Porter3cc08dc2006-01-23 15:27:49 +01002537/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002538 * Fill in the dac_nids table from the parsed pin configuration
2539 * This function only works when every pin in line_out_pins[]
2540 * contains atleast one DAC in its connection list. Some 92xx
2541 * codecs are not connected directly to a DAC, such as the 9200
2542 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002543 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002544static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002545 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002546{
2547 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002548 int i, j, conn_len = 0;
2549 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2550 unsigned int wcaps, wtype;
2551
Mattc7d4b2f2005-06-27 14:59:41 +02002552 for (i = 0; i < cfg->line_outs; i++) {
2553 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002554 conn_len = snd_hda_get_connections(codec, nid, conn,
2555 HDA_MAX_CONNECTIONS);
2556 for (j = 0; j < conn_len; j++) {
2557 wcaps = snd_hda_param_read(codec, conn[j],
2558 AC_PAR_AUDIO_WIDGET_CAP);
2559 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002560 if (wtype != AC_WID_AUD_OUT ||
2561 (wcaps & AC_WCAP_DIGITAL))
2562 continue;
2563 /* conn[j] is a DAC routed to this line-out */
2564 if (!is_in_dac_nids(spec, conn[j]))
2565 break;
2566 }
2567
2568 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002569 if (spec->multiout.num_dacs > 0) {
2570 /* we have already working output pins,
2571 * so let's drop the broken ones again
2572 */
2573 cfg->line_outs = spec->multiout.num_dacs;
2574 break;
2575 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002576 /* error out, no available DAC found */
2577 snd_printk(KERN_ERR
2578 "%s: No available DAC for pin 0x%x\n",
2579 __func__, nid);
2580 return -ENODEV;
2581 }
2582
2583 spec->multiout.dac_nids[i] = conn[j];
2584 spec->multiout.num_dacs++;
2585 if (conn_len > 1) {
2586 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002587 snd_hda_codec_write_cache(codec, nid, 0,
2588 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002589
2590 }
Mattc7d4b2f2005-06-27 14:59:41 +02002591 }
2592
Steve Longerbeam7b043892007-05-03 20:50:03 +02002593 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2594 spec->multiout.num_dacs,
2595 spec->multiout.dac_nids[0],
2596 spec->multiout.dac_nids[1],
2597 spec->multiout.dac_nids[2],
2598 spec->multiout.dac_nids[3],
2599 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002600 return 0;
2601}
2602
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002603/* create volume control/switch for the given prefx type */
2604static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2605{
2606 char name[32];
2607 int err;
2608
2609 sprintf(name, "%s Playback Volume", pfx);
2610 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2611 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2612 if (err < 0)
2613 return err;
2614 sprintf(name, "%s Playback Switch", pfx);
2615 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2616 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2617 if (err < 0)
2618 return err;
2619 return 0;
2620}
2621
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002622static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2623{
2624 if (!spec->multiout.hp_nid)
2625 spec->multiout.hp_nid = nid;
2626 else if (spec->multiout.num_dacs > 4) {
2627 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2628 return 1;
2629 } else {
2630 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2631 spec->multiout.num_dacs++;
2632 }
2633 return 0;
2634}
2635
2636static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2637{
2638 if (is_in_dac_nids(spec, nid))
2639 return 1;
2640 if (spec->multiout.hp_nid == nid)
2641 return 1;
2642 return 0;
2643}
2644
Mattc7d4b2f2005-06-27 14:59:41 +02002645/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002646static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002647 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002648{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002649 static const char *chname[4] = {
2650 "Front", "Surround", NULL /*CLFE*/, "Side"
2651 };
Mattc7d4b2f2005-06-27 14:59:41 +02002652 hda_nid_t nid;
2653 int i, err;
2654
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002655 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002656 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002657
2658
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002659 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002660 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002661 continue;
2662
2663 nid = spec->multiout.dac_nids[i];
2664
2665 if (i == 2) {
2666 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002667 err = create_controls(spec, "Center", nid, 1);
2668 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002669 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002670 err = create_controls(spec, "LFE", nid, 2);
2671 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002672 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002673
2674 wid_caps = get_wcaps(codec, nid);
2675
2676 if (wid_caps & AC_WCAP_LR_SWAP) {
2677 err = stac92xx_add_control(spec,
2678 STAC_CTL_WIDGET_CLFE_SWITCH,
2679 "Swap Center/LFE Playback Switch", nid);
2680
2681 if (err < 0)
2682 return err;
2683 }
2684
Mattc7d4b2f2005-06-27 14:59:41 +02002685 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002686 err = create_controls(spec, chname[i], nid, 3);
2687 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002688 return err;
2689 }
2690 }
2691
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002692 if (cfg->hp_outs > 1) {
2693 err = stac92xx_add_control(spec,
2694 STAC_CTL_WIDGET_HP_SWITCH,
2695 "Headphone as Line Out Switch", 0);
2696 if (err < 0)
2697 return err;
2698 }
2699
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002700 if (spec->line_switch) {
2701 nid = cfg->input_pins[AUTO_PIN_LINE];
2702 pincap = snd_hda_param_read(codec, nid,
2703 AC_PAR_PIN_CAP);
2704 if (pincap & AC_PINCAP_OUT) {
2705 err = stac92xx_add_control(spec,
2706 STAC_CTL_WIDGET_IO_SWITCH,
2707 "Line In as Output Switch", nid << 8);
2708 if (err < 0)
2709 return err;
2710 }
2711 }
Matt Porter403d1942005-11-29 15:00:51 +01002712
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002713 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002714 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002715 unsigned int mic_pin = AUTO_PIN_MIC;
2716again:
2717 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002718 def_conf = snd_hda_codec_read(codec, nid, 0,
2719 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002720 /* some laptops have an internal analog microphone
2721 * which can't be used as a output */
2722 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2723 pincap = snd_hda_param_read(codec, nid,
2724 AC_PAR_PIN_CAP);
2725 if (pincap & AC_PINCAP_OUT) {
2726 err = stac92xx_add_control(spec,
2727 STAC_CTL_WIDGET_IO_SWITCH,
2728 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002729 nid = snd_hda_codec_read(codec, nid, 0,
2730 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2731 if (!check_in_dac_nids(spec, nid))
2732 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002733 if (err < 0)
2734 return err;
2735 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002736 } else if (mic_pin == AUTO_PIN_MIC) {
2737 mic_pin = AUTO_PIN_FRONT_MIC;
2738 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002739 }
2740 }
Matt Porter403d1942005-11-29 15:00:51 +01002741
Mattc7d4b2f2005-06-27 14:59:41 +02002742 return 0;
2743}
2744
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002745/* add playback controls for Speaker and HP outputs */
2746static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2747 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002748{
2749 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002750 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002751 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002752
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002753 old_num_dacs = spec->multiout.num_dacs;
2754 for (i = 0; i < cfg->hp_outs; i++) {
2755 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2756 if (wid_caps & AC_WCAP_UNSOL_CAP)
2757 spec->hp_detect = 1;
2758 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2759 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2760 if (check_in_dac_nids(spec, nid))
2761 nid = 0;
2762 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002763 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002764 add_spec_dacs(spec, nid);
2765 }
2766 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002767 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002768 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2769 if (check_in_dac_nids(spec, nid))
2770 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002771 if (! nid)
2772 continue;
2773 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002774 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002775 for (i = 0; i < cfg->line_outs; i++) {
2776 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2777 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2778 if (check_in_dac_nids(spec, nid))
2779 nid = 0;
2780 if (! nid)
2781 continue;
2782 add_spec_dacs(spec, nid);
2783 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002784 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2785 static const char *pfxs[] = {
2786 "Speaker", "External Speaker", "Speaker2",
2787 };
2788 err = create_controls(spec, pfxs[i - old_num_dacs],
2789 spec->multiout.dac_nids[i], 3);
2790 if (err < 0)
2791 return err;
2792 }
2793 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002794 err = create_controls(spec, "Headphone",
2795 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002796 if (err < 0)
2797 return err;
2798 }
Mattc7d4b2f2005-06-27 14:59:41 +02002799
2800 return 0;
2801}
2802
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002803/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002804static const char *stac92xx_mono_labels[4] = {
2805 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002806};
2807
2808/* create mono mux for mono out on capable codecs */
2809static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2810{
2811 struct sigmatel_spec *spec = codec->spec;
2812 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2813 int i, num_cons;
2814 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2815
2816 num_cons = snd_hda_get_connections(codec,
2817 spec->mono_nid,
2818 con_lst,
2819 HDA_MAX_NUM_INPUTS);
2820 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2821 return -EINVAL;
2822
2823 for (i = 0; i < num_cons; i++) {
2824 mono_mux->items[mono_mux->num_items].label =
2825 stac92xx_mono_labels[i];
2826 mono_mux->items[mono_mux->num_items].index = i;
2827 mono_mux->num_items++;
2828 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002829
2830 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2831 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002832}
2833
Matthew Ranostay1cd22242008-07-18 18:20:52 +02002834/* create PC beep volume controls */
2835static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
2836 hda_nid_t nid)
2837{
2838 struct sigmatel_spec *spec = codec->spec;
2839 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
2840 int err;
2841
2842 /* check for mute support for the the amp */
2843 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
2844 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2845 "PC Beep Playback Switch",
2846 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2847 if (err < 0)
2848 return err;
2849 }
2850
2851 /* check to see if there is volume support for the amp */
2852 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2853 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2854 "PC Beep Playback Volume",
2855 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2856 if (err < 0)
2857 return err;
2858 }
2859 return 0;
2860}
2861
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002862static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
2863{
2864 struct sigmatel_spec *spec = codec->spec;
2865 int wcaps, nid, i, err = 0;
2866
2867 for (i = 0; i < spec->num_muxes; i++) {
2868 nid = spec->mux_nids[i];
2869 wcaps = get_wcaps(codec, nid);
2870
2871 if (wcaps & AC_WCAP_OUT_AMP) {
2872 err = stac92xx_add_control_idx(spec,
2873 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
2874 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2875 if (err < 0)
2876 return err;
2877 }
2878 }
2879 return 0;
2880};
2881
Matthew Ranostayd9737752008-09-07 12:03:41 +02002882static const char *stac92xx_spdif_labels[3] = {
2883 "Digital Playback", "Analog Mux 1", "Analog Mux 2"
2884};
2885
2886static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
2887{
2888 struct sigmatel_spec *spec = codec->spec;
2889 struct hda_input_mux *spdif_mux = &spec->private_smux;
2890 int i, num_cons;
2891 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_spdif_labels)];
2892
2893 num_cons = snd_hda_get_connections(codec,
2894 spec->smux_nids[0],
2895 con_lst,
2896 HDA_MAX_NUM_INPUTS);
2897 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_spdif_labels))
2898 return -EINVAL;
2899
2900 for (i = 0; i < num_cons; i++) {
2901 spdif_mux->items[spdif_mux->num_items].label =
2902 stac92xx_spdif_labels[i];
2903 spdif_mux->items[spdif_mux->num_items].index = i;
2904 spdif_mux->num_items++;
2905 }
2906
2907 return 0;
2908}
2909
Matt Porter8b657272006-10-26 17:12:59 +02002910/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002911static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002912 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2913 "Digital Mic 3", "Digital Mic 4"
2914};
2915
2916/* create playback/capture controls for input pins on dmic capable codecs */
2917static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2918 const struct auto_pin_cfg *cfg)
2919{
2920 struct sigmatel_spec *spec = codec->spec;
2921 struct hda_input_mux *dimux = &spec->private_dimux;
2922 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002923 int err, i, j;
2924 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002925
2926 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2927 dimux->items[dimux->num_items].index = 0;
2928 dimux->num_items++;
2929
2930 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002931 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002932 int index;
2933 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002934 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002935 unsigned int def_conf;
2936
2937 def_conf = snd_hda_codec_read(codec,
2938 spec->dmic_nids[i],
2939 0,
2940 AC_VERB_GET_CONFIG_DEFAULT,
2941 0);
2942 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2943 continue;
2944
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002945 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002946 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002947 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002948 con_lst,
2949 HDA_MAX_NUM_INPUTS);
2950 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002951 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002952 index = j;
2953 goto found;
2954 }
2955 continue;
2956found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002957 wcaps = get_wcaps(codec, nid) &
2958 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002959
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002960 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002961 sprintf(name, "%s Capture Volume",
2962 stac92xx_dmic_labels[dimux->num_items]);
2963
2964 err = stac92xx_add_control(spec,
2965 STAC_CTL_WIDGET_VOL,
2966 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002967 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2968 (wcaps & AC_WCAP_OUT_AMP) ?
2969 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002970 if (err < 0)
2971 return err;
2972 }
2973
Matt Porter8b657272006-10-26 17:12:59 +02002974 dimux->items[dimux->num_items].label =
2975 stac92xx_dmic_labels[dimux->num_items];
2976 dimux->items[dimux->num_items].index = index;
2977 dimux->num_items++;
2978 }
2979
2980 return 0;
2981}
2982
Mattc7d4b2f2005-06-27 14:59:41 +02002983/* create playback/capture controls for input pins */
2984static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2985{
2986 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002987 struct hda_input_mux *imux = &spec->private_imux;
2988 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2989 int i, j, k;
2990
2991 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002992 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002993
Takashi Iwai314634b2006-09-21 11:56:18 +02002994 if (!cfg->input_pins[i])
2995 continue;
2996 index = -1;
2997 for (j = 0; j < spec->num_muxes; j++) {
2998 int num_cons;
2999 num_cons = snd_hda_get_connections(codec,
3000 spec->mux_nids[j],
3001 con_lst,
3002 HDA_MAX_NUM_INPUTS);
3003 for (k = 0; k < num_cons; k++)
3004 if (con_lst[k] == cfg->input_pins[i]) {
3005 index = k;
3006 goto found;
3007 }
Mattc7d4b2f2005-06-27 14:59:41 +02003008 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003009 continue;
3010 found:
3011 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3012 imux->items[imux->num_items].index = index;
3013 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003014 }
3015
Steve Longerbeam7b043892007-05-03 20:50:03 +02003016 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003017 /*
3018 * Set the current input for the muxes.
3019 * The STAC9221 has two input muxes with identical source
3020 * NID lists. Hopefully this won't get confused.
3021 */
3022 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003023 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3024 AC_VERB_SET_CONNECT_SEL,
3025 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003026 }
3027 }
3028
Mattc7d4b2f2005-06-27 14:59:41 +02003029 return 0;
3030}
3031
Mattc7d4b2f2005-06-27 14:59:41 +02003032static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3033{
3034 struct sigmatel_spec *spec = codec->spec;
3035 int i;
3036
3037 for (i = 0; i < spec->autocfg.line_outs; i++) {
3038 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3039 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3040 }
3041}
3042
3043static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3044{
3045 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003046 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003047
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003048 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3049 hda_nid_t pin;
3050 pin = spec->autocfg.hp_pins[i];
3051 if (pin) /* connect to front */
3052 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3053 }
3054 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3055 hda_nid_t pin;
3056 pin = spec->autocfg.speaker_pins[i];
3057 if (pin) /* connect to front */
3058 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3059 }
Mattc7d4b2f2005-06-27 14:59:41 +02003060}
3061
Matt Porter3cc08dc2006-01-23 15:27:49 +01003062static 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 +02003063{
3064 struct sigmatel_spec *spec = codec->spec;
3065 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003066 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003067
Matt Porter8b657272006-10-26 17:12:59 +02003068 if ((err = snd_hda_parse_pin_def_config(codec,
3069 &spec->autocfg,
3070 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003071 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003072 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003073 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003074
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003075 /* If we have no real line-out pin and multiple hp-outs, HPs should
3076 * be set up as multi-channel outputs.
3077 */
3078 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3079 spec->autocfg.hp_outs > 1) {
3080 /* Copy hp_outs to line_outs, backup line_outs in
3081 * speaker_outs so that the following routines can handle
3082 * HP pins as primary outputs.
3083 */
3084 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3085 sizeof(spec->autocfg.line_out_pins));
3086 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3087 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3088 sizeof(spec->autocfg.hp_pins));
3089 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3090 hp_speaker_swap = 1;
3091 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003092 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003093 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3094 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003095 u32 caps = query_amp_caps(codec,
3096 spec->autocfg.mono_out_pin, dir);
3097 hda_nid_t conn_list[1];
3098
3099 /* get the mixer node and then the mono mux if it exists */
3100 if (snd_hda_get_connections(codec,
3101 spec->autocfg.mono_out_pin, conn_list, 1) &&
3102 snd_hda_get_connections(codec, conn_list[0],
3103 conn_list, 1)) {
3104
3105 int wcaps = get_wcaps(codec, conn_list[0]);
3106 int wid_type = (wcaps & AC_WCAP_TYPE)
3107 >> AC_WCAP_TYPE_SHIFT;
3108 /* LR swap check, some stac925x have a mux that
3109 * changes the DACs output path instead of the
3110 * mono-mux path.
3111 */
3112 if (wid_type == AC_WID_AUD_SEL &&
3113 !(wcaps & AC_WCAP_LR_SWAP))
3114 spec->mono_nid = conn_list[0];
3115 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003116 if (dir) {
3117 hda_nid_t nid = spec->autocfg.mono_out_pin;
3118
3119 /* most mono outs have a least a mute/unmute switch */
3120 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3121 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3122 "Mono Playback Switch",
3123 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003124 if (err < 0)
3125 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003126 /* check for volume support for the amp */
3127 if ((caps & AC_AMPCAP_NUM_STEPS)
3128 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3129 err = stac92xx_add_control(spec,
3130 STAC_CTL_WIDGET_VOL,
3131 "Mono Playback Volume",
3132 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3133 if (err < 0)
3134 return err;
3135 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003136 }
3137
3138 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3139 AC_PINCTL_OUT_EN);
3140 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003141
Matt Porter403d1942005-11-29 15:00:51 +01003142 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3143 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003144 if (spec->multiout.num_dacs == 0)
3145 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3146 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003147
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003148 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3149
3150 if (err < 0)
3151 return err;
3152
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003153 /* setup analog beep controls */
3154 if (spec->anabeep_nid > 0) {
3155 err = stac92xx_auto_create_beep_ctls(codec,
3156 spec->anabeep_nid);
3157 if (err < 0)
3158 return err;
3159 }
3160
3161 /* setup digital beep controls and input device */
3162#ifdef CONFIG_SND_HDA_INPUT_BEEP
3163 if (spec->digbeep_nid > 0) {
3164 hda_nid_t nid = spec->digbeep_nid;
3165
3166 err = stac92xx_auto_create_beep_ctls(codec, nid);
3167 if (err < 0)
3168 return err;
3169 err = snd_hda_attach_beep_device(codec, nid);
3170 if (err < 0)
3171 return err;
3172 }
3173#endif
3174
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003175 if (hp_speaker_swap == 1) {
3176 /* Restore the hp_outs and line_outs */
3177 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3178 sizeof(spec->autocfg.line_out_pins));
3179 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3180 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3181 sizeof(spec->autocfg.speaker_pins));
3182 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3183 memset(spec->autocfg.speaker_pins, 0,
3184 sizeof(spec->autocfg.speaker_pins));
3185 spec->autocfg.speaker_outs = 0;
3186 }
3187
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003188 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3189
3190 if (err < 0)
3191 return err;
3192
3193 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3194
3195 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003196 return err;
3197
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003198 if (spec->mono_nid > 0) {
3199 err = stac92xx_auto_create_mono_output_ctls(codec);
3200 if (err < 0)
3201 return err;
3202 }
3203
Matt Porter8b657272006-10-26 17:12:59 +02003204 if (spec->num_dmics > 0)
3205 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3206 &spec->autocfg)) < 0)
3207 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003208 if (spec->num_muxes > 0) {
3209 err = stac92xx_auto_create_mux_input_ctls(codec);
3210 if (err < 0)
3211 return err;
3212 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003213 if (spec->num_smuxes > 0) {
3214 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3215 if (err < 0)
3216 return err;
3217 }
Matt Porter8b657272006-10-26 17:12:59 +02003218
Mattc7d4b2f2005-06-27 14:59:41 +02003219 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003220 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003221 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003222
Takashi Iwai82bc9552006-03-21 11:24:42 +01003223 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003224 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003225 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003226 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003227
3228 if (spec->kctl_alloc)
3229 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3230
3231 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003232 if (!spec->dinput_mux)
3233 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003234 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003235 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003236
3237 return 1;
3238}
3239
Takashi Iwai82bc9552006-03-21 11:24:42 +01003240/* add playback controls for HP output */
3241static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3242 struct auto_pin_cfg *cfg)
3243{
3244 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003245 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003246 unsigned int wid_caps;
3247
3248 if (! pin)
3249 return 0;
3250
3251 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003252 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003253 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003254
3255 return 0;
3256}
3257
Richard Fish160ea0d2006-09-06 13:58:25 +02003258/* add playback controls for LFE output */
3259static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3260 struct auto_pin_cfg *cfg)
3261{
3262 struct sigmatel_spec *spec = codec->spec;
3263 int err;
3264 hda_nid_t lfe_pin = 0x0;
3265 int i;
3266
3267 /*
3268 * search speaker outs and line outs for a mono speaker pin
3269 * with an amp. If one is found, add LFE controls
3270 * for it.
3271 */
3272 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3273 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003274 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003275 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3276 if (wcaps == AC_WCAP_OUT_AMP)
3277 /* found a mono speaker with an amp, must be lfe */
3278 lfe_pin = pin;
3279 }
3280
3281 /* if speaker_outs is 0, then speakers may be in line_outs */
3282 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3283 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3284 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003285 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003286 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003287 AC_VERB_GET_CONFIG_DEFAULT,
3288 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003289 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003290 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003291 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3292 if (wcaps == AC_WCAP_OUT_AMP)
3293 /* found a mono speaker with an amp,
3294 must be lfe */
3295 lfe_pin = pin;
3296 }
3297 }
3298 }
3299
3300 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003301 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003302 if (err < 0)
3303 return err;
3304 }
3305
3306 return 0;
3307}
3308
Mattc7d4b2f2005-06-27 14:59:41 +02003309static int stac9200_parse_auto_config(struct hda_codec *codec)
3310{
3311 struct sigmatel_spec *spec = codec->spec;
3312 int err;
3313
Kailang Yangdf694da2005-12-05 19:42:22 +01003314 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003315 return err;
3316
3317 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3318 return err;
3319
Takashi Iwai82bc9552006-03-21 11:24:42 +01003320 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3321 return err;
3322
Richard Fish160ea0d2006-09-06 13:58:25 +02003323 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3324 return err;
3325
Takashi Iwai82bc9552006-03-21 11:24:42 +01003326 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003327 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003328 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003329 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003330
3331 if (spec->kctl_alloc)
3332 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3333
3334 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003335 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003336
3337 return 1;
3338}
3339
Sam Revitch62fe78e2006-05-10 15:09:17 +02003340/*
3341 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3342 * funky external mute control using GPIO pins.
3343 */
3344
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003345static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003346 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003347{
3348 unsigned int gpiostate, gpiomask, gpiodir;
3349
3350 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3351 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003352 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003353
3354 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3355 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003356 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003357
3358 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3359 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003360 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003361
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003362 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003363 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3364
3365 snd_hda_codec_write(codec, codec->afg, 0,
3366 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003367 snd_hda_codec_read(codec, codec->afg, 0,
3368 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003369
3370 msleep(1);
3371
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003372 snd_hda_codec_read(codec, codec->afg, 0,
3373 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003374}
3375
Takashi Iwai314634b2006-09-21 11:56:18 +02003376static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3377 unsigned int event)
3378{
3379 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003380 snd_hda_codec_write_cache(codec, nid, 0,
3381 AC_VERB_SET_UNSOLICITED_ENABLE,
3382 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003383}
3384
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003385static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3386{
3387 int i;
3388 for (i = 0; i < cfg->hp_outs; i++)
3389 if (cfg->hp_pins[i] == nid)
3390 return 1; /* nid is a HP-Out */
3391
3392 return 0; /* nid is not a HP-Out */
3393};
3394
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003395static void stac92xx_power_down(struct hda_codec *codec)
3396{
3397 struct sigmatel_spec *spec = codec->spec;
3398
3399 /* power down inactive DACs */
3400 hda_nid_t *dac;
3401 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003402 if (!is_in_dac_nids(spec, *dac) &&
3403 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003404 snd_hda_codec_write_cache(codec, *dac, 0,
3405 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3406}
3407
Mattc7d4b2f2005-06-27 14:59:41 +02003408static int stac92xx_init(struct hda_codec *codec)
3409{
3410 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003411 struct auto_pin_cfg *cfg = &spec->autocfg;
3412 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003413
Mattc7d4b2f2005-06-27 14:59:41 +02003414 snd_hda_sequence_write(codec, spec->init);
3415
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003416 /* power down adcs initially */
3417 if (spec->powerdown_adcs)
3418 for (i = 0; i < spec->num_adcs; i++)
3419 snd_hda_codec_write_cache(codec,
3420 spec->adc_nids[i], 0,
3421 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003422 /* set up pins */
3423 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003424 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003425 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003426 enable_pin_detect(codec, cfg->hp_pins[i],
3427 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003428 /* force to enable the first line-out; the others are set up
3429 * in unsol_event
3430 */
3431 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3432 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003433 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003434 /* fake event to set up pins */
3435 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3436 } else {
3437 stac92xx_auto_init_multi_out(codec);
3438 stac92xx_auto_init_hp_out(codec);
3439 }
3440 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003441 hda_nid_t nid = cfg->input_pins[i];
3442 if (nid) {
3443 unsigned int pinctl = AC_PINCTL_IN_EN;
3444 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3445 pinctl |= stac92xx_get_vref(codec, nid);
3446 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3447 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003448 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003449 for (i = 0; i < spec->num_dmics; i++)
3450 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3451 AC_PINCTL_IN_EN);
3452 for (i = 0; i < spec->num_pwrs; i++) {
3453 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3454 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3455 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3456 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003457 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3458 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003459 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003460 /* outputs are only ports capable of power management
3461 * any attempts on powering down a input port cause the
3462 * referenced VREF to act quirky.
3463 */
3464 if (pinctl & AC_PINCTL_IN_EN)
3465 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003466 /* skip any ports that don't have jacks since presence
3467 * detection is useless */
3468 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003469 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003470 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3471 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3472 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003473 if (spec->dac_list)
3474 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003475 if (cfg->dig_out_pin)
3476 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3477 AC_PINCTL_OUT_EN);
3478 if (cfg->dig_in_pin)
3479 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3480 AC_PINCTL_IN_EN);
3481
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003482 stac_gpio_set(codec, spec->gpio_mask,
3483 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003484
Mattc7d4b2f2005-06-27 14:59:41 +02003485 return 0;
3486}
3487
Matt2f2f4252005-04-13 14:45:30 +02003488static void stac92xx_free(struct hda_codec *codec)
3489{
Mattc7d4b2f2005-06-27 14:59:41 +02003490 struct sigmatel_spec *spec = codec->spec;
3491 int i;
3492
3493 if (! spec)
3494 return;
3495
3496 if (spec->kctl_alloc) {
3497 for (i = 0; i < spec->num_kctl_used; i++)
3498 kfree(spec->kctl_alloc[i].name);
3499 kfree(spec->kctl_alloc);
3500 }
3501
Richard Fish11b44bb2006-08-23 18:31:34 +02003502 if (spec->bios_pin_configs)
3503 kfree(spec->bios_pin_configs);
3504
Mattc7d4b2f2005-06-27 14:59:41 +02003505 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003506 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003507}
3508
Matt4e550962005-07-04 17:51:39 +02003509static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3510 unsigned int flag)
3511{
3512 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3513 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003514
Takashi Iwaif9acba42007-05-29 18:01:06 +02003515 if (pin_ctl & AC_PINCTL_IN_EN) {
3516 /*
3517 * we need to check the current set-up direction of
3518 * shared input pins since they can be switched via
3519 * "xxx as Output" mixer switch
3520 */
3521 struct sigmatel_spec *spec = codec->spec;
3522 struct auto_pin_cfg *cfg = &spec->autocfg;
3523 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3524 spec->line_switch) ||
3525 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3526 spec->mic_switch))
3527 return;
3528 }
3529
Steve Longerbeam7b043892007-05-03 20:50:03 +02003530 /* if setting pin direction bits, clear the current
3531 direction bits first */
3532 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3533 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3534
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003535 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003536 AC_VERB_SET_PIN_WIDGET_CONTROL,
3537 pin_ctl | flag);
3538}
3539
3540static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3541 unsigned int flag)
3542{
3543 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3544 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003545 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003546 AC_VERB_SET_PIN_WIDGET_CONTROL,
3547 pin_ctl & ~flag);
3548}
3549
Jiang Zhe40c1d302007-11-12 13:05:16 +01003550static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003551{
3552 if (!nid)
3553 return 0;
3554 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003555 & (1 << 31)) {
3556 unsigned int pinctl;
3557 pinctl = snd_hda_codec_read(codec, nid, 0,
3558 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3559 if (pinctl & AC_PINCTL_IN_EN)
3560 return 0; /* mic- or line-input */
3561 else
3562 return 1; /* HP-output */
3563 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003564 return 0;
3565}
3566
3567static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003568{
3569 struct sigmatel_spec *spec = codec->spec;
3570 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003571 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003572 int i, presence;
3573
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003574 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003575 if (spec->gpio_mute)
3576 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3577 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3578
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003579 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003580 if (presence)
3581 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003582 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3583 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003584 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003585 }
Matt4e550962005-07-04 17:51:39 +02003586
3587 if (presence) {
3588 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003589 if (spec->hp_switch)
3590 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003591 for (i = 0; i < cfg->line_outs; i++)
3592 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3593 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003594 for (i = 0; i < cfg->speaker_outs; i++)
3595 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3596 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003597 if (spec->eapd_mask)
3598 stac_gpio_set(codec, spec->gpio_mask,
3599 spec->gpio_dir, spec->gpio_data &
3600 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003601 } else {
3602 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003603 if (spec->hp_switch)
3604 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003605 for (i = 0; i < cfg->line_outs; i++)
3606 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3607 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003608 for (i = 0; i < cfg->speaker_outs; i++)
3609 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3610 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003611 if (spec->eapd_mask)
3612 stac_gpio_set(codec, spec->gpio_mask,
3613 spec->gpio_dir, spec->gpio_data |
3614 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003615 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003616 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3617 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003618}
3619
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003620static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3621{
3622 struct sigmatel_spec *spec = codec->spec;
3623 hda_nid_t nid = spec->pwr_nids[idx];
3624 int presence, val;
3625 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3626 & 0x000000ff;
3627 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003628
3629 /* several codecs have two power down bits */
3630 if (spec->pwr_mapping)
3631 idx = spec->pwr_mapping[idx];
3632 else
3633 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003634
3635 if (presence)
3636 val &= ~idx;
3637 else
3638 val |= idx;
3639
3640 /* power down unused output ports */
3641 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3642};
3643
Takashi Iwai314634b2006-09-21 11:56:18 +02003644static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3645{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003646 struct sigmatel_spec *spec = codec->spec;
3647 int idx = res >> 26 & 0x0f;
3648
3649 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003650 case STAC_HP_EVENT:
3651 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003652 /* fallthru */
3653 case STAC_PWR_EVENT:
3654 if (spec->num_pwrs > 0)
3655 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003656 }
3657}
3658
Takashi Iwaicb53c622007-08-10 17:21:45 +02003659#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003660static int stac92xx_resume(struct hda_codec *codec)
3661{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003662 struct sigmatel_spec *spec = codec->spec;
3663
Richard Fish11b44bb2006-08-23 18:31:34 +02003664 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003665 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003666 stac_gpio_set(codec, spec->gpio_mask,
3667 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003668 snd_hda_codec_resume_amp(codec);
3669 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003670 /* power down inactive DACs */
3671 if (spec->dac_list)
3672 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003673 /* invoke unsolicited event to reset the HP state */
3674 if (spec->hp_detect)
3675 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003676 return 0;
3677}
3678#endif
3679
Matt2f2f4252005-04-13 14:45:30 +02003680static struct hda_codec_ops stac92xx_patch_ops = {
3681 .build_controls = stac92xx_build_controls,
3682 .build_pcms = stac92xx_build_pcms,
3683 .init = stac92xx_init,
3684 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003685 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003686#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003687 .resume = stac92xx_resume,
3688#endif
Matt2f2f4252005-04-13 14:45:30 +02003689};
3690
3691static int patch_stac9200(struct hda_codec *codec)
3692{
3693 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003694 int err;
Matt2f2f4252005-04-13 14:45:30 +02003695
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003696 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003697 if (spec == NULL)
3698 return -ENOMEM;
3699
3700 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003701 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003702 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003703 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3704 stac9200_models,
3705 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003706 if (spec->board_config < 0) {
3707 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3708 err = stac92xx_save_bios_config_regs(codec);
3709 if (err < 0) {
3710 stac92xx_free(codec);
3711 return err;
3712 }
3713 spec->pin_configs = spec->bios_pin_configs;
3714 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003715 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3716 stac92xx_set_config_regs(codec);
3717 }
Matt2f2f4252005-04-13 14:45:30 +02003718
3719 spec->multiout.max_channels = 2;
3720 spec->multiout.num_dacs = 1;
3721 spec->multiout.dac_nids = stac9200_dac_nids;
3722 spec->adc_nids = stac9200_adc_nids;
3723 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003724 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003725 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003726 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003727 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003728
Tobin Davisbf277782008-02-03 20:31:47 +01003729 if (spec->board_config == STAC_9200_GATEWAY ||
3730 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003731 spec->init = stac9200_eapd_init;
3732 else
3733 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003734 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003735
Takashi Iwai117f2572008-03-18 09:53:23 +01003736 if (spec->board_config == STAC_9200_PANASONIC) {
3737 spec->gpio_mask = spec->gpio_dir = 0x09;
3738 spec->gpio_data = 0x00;
3739 }
3740
Mattc7d4b2f2005-06-27 14:59:41 +02003741 err = stac9200_parse_auto_config(codec);
3742 if (err < 0) {
3743 stac92xx_free(codec);
3744 return err;
3745 }
Matt2f2f4252005-04-13 14:45:30 +02003746
3747 codec->patch_ops = stac92xx_patch_ops;
3748
3749 return 0;
3750}
3751
Tobin Davis8e21c342007-01-08 11:04:17 +01003752static int patch_stac925x(struct hda_codec *codec)
3753{
3754 struct sigmatel_spec *spec;
3755 int err;
3756
3757 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3758 if (spec == NULL)
3759 return -ENOMEM;
3760
3761 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003762 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003763 spec->pin_nids = stac925x_pin_nids;
3764 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3765 stac925x_models,
3766 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003767 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003768 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003769 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3770 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003771 err = stac92xx_save_bios_config_regs(codec);
3772 if (err < 0) {
3773 stac92xx_free(codec);
3774 return err;
3775 }
3776 spec->pin_configs = spec->bios_pin_configs;
3777 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3778 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3779 stac92xx_set_config_regs(codec);
3780 }
3781
3782 spec->multiout.max_channels = 2;
3783 spec->multiout.num_dacs = 1;
3784 spec->multiout.dac_nids = stac925x_dac_nids;
3785 spec->adc_nids = stac925x_adc_nids;
3786 spec->mux_nids = stac925x_mux_nids;
3787 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003788 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003789 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003790 switch (codec->vendor_id) {
3791 case 0x83847632: /* STAC9202 */
3792 case 0x83847633: /* STAC9202D */
3793 case 0x83847636: /* STAC9251 */
3794 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003795 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003796 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003797 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3798 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003799 break;
3800 default:
3801 spec->num_dmics = 0;
3802 break;
3803 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003804
3805 spec->init = stac925x_core_init;
3806 spec->mixer = stac925x_mixer;
3807
3808 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003809 if (!err) {
3810 if (spec->board_config < 0) {
3811 printk(KERN_WARNING "hda_codec: No auto-config is "
3812 "available, default to model=ref\n");
3813 spec->board_config = STAC_925x_REF;
3814 goto again;
3815 }
3816 err = -EINVAL;
3817 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003818 if (err < 0) {
3819 stac92xx_free(codec);
3820 return err;
3821 }
3822
3823 codec->patch_ops = stac92xx_patch_ops;
3824
3825 return 0;
3826}
3827
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003828static struct hda_input_mux stac92hd73xx_dmux = {
3829 .num_items = 4,
3830 .items = {
3831 { "Analog Inputs", 0x0b },
3832 { "CD", 0x08 },
3833 { "Digital Mic 1", 0x09 },
3834 { "Digital Mic 2", 0x0a },
3835 }
3836};
3837
3838static int patch_stac92hd73xx(struct hda_codec *codec)
3839{
3840 struct sigmatel_spec *spec;
3841 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3842 int err = 0;
3843
3844 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3845 if (spec == NULL)
3846 return -ENOMEM;
3847
3848 codec->spec = spec;
3849 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3850 spec->pin_nids = stac92hd73xx_pin_nids;
3851 spec->board_config = snd_hda_check_board_config(codec,
3852 STAC_92HD73XX_MODELS,
3853 stac92hd73xx_models,
3854 stac92hd73xx_cfg_tbl);
3855again:
3856 if (spec->board_config < 0) {
3857 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3858 " STAC92HD73XX, using BIOS defaults\n");
3859 err = stac92xx_save_bios_config_regs(codec);
3860 if (err < 0) {
3861 stac92xx_free(codec);
3862 return err;
3863 }
3864 spec->pin_configs = spec->bios_pin_configs;
3865 } else {
3866 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3867 stac92xx_set_config_regs(codec);
3868 }
3869
3870 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3871 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3872
3873 if (spec->multiout.num_dacs < 0) {
3874 printk(KERN_WARNING "hda_codec: Could not determine "
3875 "number of channels defaulting to DAC count\n");
3876 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3877 }
3878
3879 switch (spec->multiout.num_dacs) {
3880 case 0x3: /* 6 Channel */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003881 spec->multiout.hp_nid = 0x17;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003882 spec->mixer = stac92hd73xx_6ch_mixer;
3883 spec->init = stac92hd73xx_6ch_core_init;
3884 break;
3885 case 0x4: /* 8 Channel */
3886 spec->multiout.hp_nid = 0x18;
3887 spec->mixer = stac92hd73xx_8ch_mixer;
3888 spec->init = stac92hd73xx_8ch_core_init;
3889 break;
3890 case 0x5: /* 10 Channel */
3891 spec->multiout.hp_nid = 0x19;
3892 spec->mixer = stac92hd73xx_10ch_mixer;
3893 spec->init = stac92hd73xx_10ch_core_init;
3894 };
3895
3896 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3897 spec->aloopback_mask = 0x01;
3898 spec->aloopback_shift = 8;
3899
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003900 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003901 spec->mux_nids = stac92hd73xx_mux_nids;
3902 spec->adc_nids = stac92hd73xx_adc_nids;
3903 spec->dmic_nids = stac92hd73xx_dmic_nids;
3904 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003905 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003906
3907 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3908 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003909 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02003910 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003911 spec->dinput_mux = &stac92hd73xx_dmux;
3912 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003913 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003914 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003915
Matthew Ranostaya7662642008-02-21 07:51:14 +01003916 switch (spec->board_config) {
3917 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003918 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003919 switch (codec->subsystem_id) {
3920 case 0x1028025e: /* Analog Mics */
3921 case 0x1028025f:
3922 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3923 spec->num_dmics = 0;
3924 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003925 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003926 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003927 spec->init = dell_m6_core_init;
3928 /* fall-through */
3929 case 0x10280254:
3930 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003931 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3932 spec->num_dmics = 1;
3933 break;
3934 case 0x10280256: /* Both */
3935 case 0x10280057:
3936 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3937 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3938 spec->num_dmics = 1;
3939 break;
3940 }
3941 break;
3942 default:
3943 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3944 }
3945
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003946 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3947 spec->pwr_nids = stac92hd73xx_pwr_nids;
3948
Matthew Ranostayd9737752008-09-07 12:03:41 +02003949 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003950
3951 if (!err) {
3952 if (spec->board_config < 0) {
3953 printk(KERN_WARNING "hda_codec: No auto-config is "
3954 "available, default to model=ref\n");
3955 spec->board_config = STAC_92HD73XX_REF;
3956 goto again;
3957 }
3958 err = -EINVAL;
3959 }
3960
3961 if (err < 0) {
3962 stac92xx_free(codec);
3963 return err;
3964 }
3965
3966 codec->patch_ops = stac92xx_patch_ops;
3967
3968 return 0;
3969}
3970
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003971static struct hda_input_mux stac92hd83xxx_dmux = {
3972 .num_items = 3,
3973 .items = {
3974 { "Analog Inputs", 0x03 },
3975 { "Digital Mic 1", 0x04 },
3976 { "Digital Mic 2", 0x05 },
3977 }
3978};
3979
3980static int patch_stac92hd83xxx(struct hda_codec *codec)
3981{
3982 struct sigmatel_spec *spec;
3983 int err;
3984
3985 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3986 if (spec == NULL)
3987 return -ENOMEM;
3988
3989 codec->spec = spec;
3990 spec->mono_nid = 0x19;
3991 spec->digbeep_nid = 0x21;
3992 spec->dmic_nids = stac92hd83xxx_dmic_nids;
3993 spec->dmux_nids = stac92hd83xxx_dmux_nids;
3994 spec->adc_nids = stac92hd83xxx_adc_nids;
3995 spec->pwr_nids = stac92hd83xxx_pwr_nids;
3996 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
3997 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
3998 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
3999
4000 spec->init = stac92hd83xxx_core_init;
4001 switch (codec->vendor_id) {
4002 case 0x111d7605:
4003 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4004 break;
4005 default:
4006 spec->num_pwrs--;
4007 spec->init++; /* switch to config #2 */
4008 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4009 }
4010
4011 spec->mixer = stac92hd83xxx_mixer;
4012 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4013 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4014 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4015 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4016 spec->dinput_mux = &stac92hd83xxx_dmux;
4017 spec->pin_nids = stac92hd83xxx_pin_nids;
4018 spec->board_config = snd_hda_check_board_config(codec,
4019 STAC_92HD83XXX_MODELS,
4020 stac92hd83xxx_models,
4021 stac92hd83xxx_cfg_tbl);
4022again:
4023 if (spec->board_config < 0) {
4024 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4025 " STAC92HD83XXX, using BIOS defaults\n");
4026 err = stac92xx_save_bios_config_regs(codec);
4027 if (err < 0) {
4028 stac92xx_free(codec);
4029 return err;
4030 }
4031 spec->pin_configs = spec->bios_pin_configs;
4032 } else {
4033 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4034 stac92xx_set_config_regs(codec);
4035 }
4036
4037 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4038 if (!err) {
4039 if (spec->board_config < 0) {
4040 printk(KERN_WARNING "hda_codec: No auto-config is "
4041 "available, default to model=ref\n");
4042 spec->board_config = STAC_92HD83XXX_REF;
4043 goto again;
4044 }
4045 err = -EINVAL;
4046 }
4047
4048 if (err < 0) {
4049 stac92xx_free(codec);
4050 return err;
4051 }
4052
4053 codec->patch_ops = stac92xx_patch_ops;
4054
4055 return 0;
4056}
4057
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004058#ifdef SND_HDA_NEEDS_RESUME
4059static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4060{
4061 struct sigmatel_spec *spec = codec->spec;
4062 int i;
4063 snd_hda_codec_write_cache(codec, codec->afg, 0,
4064 AC_VERB_SET_POWER_STATE, pwr);
4065
4066 msleep(1);
4067 for (i = 0; i < spec->num_adcs; i++) {
4068 snd_hda_codec_write_cache(codec,
4069 spec->adc_nids[i], 0,
4070 AC_VERB_SET_POWER_STATE, pwr);
4071 }
4072};
4073
4074static int stac92hd71xx_resume(struct hda_codec *codec)
4075{
4076 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4077 return stac92xx_resume(codec);
4078}
4079
4080static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4081{
4082 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4083 return 0;
4084};
4085
4086#endif
4087
4088static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4089 .build_controls = stac92xx_build_controls,
4090 .build_pcms = stac92xx_build_pcms,
4091 .init = stac92xx_init,
4092 .free = stac92xx_free,
4093 .unsol_event = stac92xx_unsol_event,
4094#ifdef SND_HDA_NEEDS_RESUME
4095 .resume = stac92hd71xx_resume,
4096 .suspend = stac92hd71xx_suspend,
4097#endif
4098};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004099
Matthew Ranostaye035b842007-11-06 11:53:55 +01004100static int patch_stac92hd71bxx(struct hda_codec *codec)
4101{
4102 struct sigmatel_spec *spec;
4103 int err = 0;
4104
4105 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4106 if (spec == NULL)
4107 return -ENOMEM;
4108
4109 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004110 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004111 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004112 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004113 spec->pin_nids = stac92hd71bxx_pin_nids;
4114 spec->board_config = snd_hda_check_board_config(codec,
4115 STAC_92HD71BXX_MODELS,
4116 stac92hd71bxx_models,
4117 stac92hd71bxx_cfg_tbl);
4118again:
4119 if (spec->board_config < 0) {
4120 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4121 " STAC92HD71BXX, using BIOS defaults\n");
4122 err = stac92xx_save_bios_config_regs(codec);
4123 if (err < 0) {
4124 stac92xx_free(codec);
4125 return err;
4126 }
4127 spec->pin_configs = spec->bios_pin_configs;
4128 } else {
4129 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4130 stac92xx_set_config_regs(codec);
4131 }
4132
Matthew Ranostay541eee82007-12-14 12:08:04 +01004133 switch (codec->vendor_id) {
4134 case 0x111d76b6: /* 4 Port without Analog Mixer */
4135 case 0x111d76b7:
4136 case 0x111d76b4: /* 6 Port without Analog Mixer */
4137 case 0x111d76b5:
4138 spec->mixer = stac92hd71bxx_mixer;
4139 spec->init = stac92hd71bxx_core_init;
4140 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004141 case 0x111d7608: /* 5 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004142 if ((codec->revision_id & 0xf) == 0 ||
4143 (codec->revision_id & 0xf) == 1) {
4144#ifdef SND_HDA_NEEDS_RESUME
4145 codec->patch_ops = stac92hd71bxx_patch_ops;
4146#endif
4147 spec->stream_delay = 40; /* 40 milliseconds */
4148 }
4149
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004150 /* no output amps */
4151 spec->num_pwrs = 0;
4152 spec->mixer = stac92hd71bxx_analog_mixer;
4153
4154 /* disable VSW */
4155 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4156 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4157 break;
4158 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004159 if ((codec->revision_id & 0xf) == 1) {
4160#ifdef SND_HDA_NEEDS_RESUME
4161 codec->patch_ops = stac92hd71bxx_patch_ops;
4162#endif
4163 spec->stream_delay = 40; /* 40 milliseconds */
4164 }
4165
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004166 /* no output amps */
4167 spec->num_pwrs = 0;
4168 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004169 default:
4170 spec->mixer = stac92hd71bxx_analog_mixer;
4171 spec->init = stac92hd71bxx_analog_core_init;
4172 }
4173
4174 spec->aloopback_mask = 0x20;
4175 spec->aloopback_shift = 0;
4176
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004177 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004178 spec->gpio_mask = 0x01;
4179 spec->gpio_dir = 0x01;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004180 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004181
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004182 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004183 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004184 spec->mux_nids = stac92hd71bxx_mux_nids;
4185 spec->adc_nids = stac92hd71bxx_adc_nids;
4186 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004187 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004188 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004189 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004190
4191 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4192 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
4193 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004194 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004195 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004196
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004197 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004198 spec->multiout.hp_nid = 0x11;
4199 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
4200
4201 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4202 if (!err) {
4203 if (spec->board_config < 0) {
4204 printk(KERN_WARNING "hda_codec: No auto-config is "
4205 "available, default to model=ref\n");
4206 spec->board_config = STAC_92HD71BXX_REF;
4207 goto again;
4208 }
4209 err = -EINVAL;
4210 }
4211
4212 if (err < 0) {
4213 stac92xx_free(codec);
4214 return err;
4215 }
4216
Matthew Ranostaye035b842007-11-06 11:53:55 +01004217 return 0;
4218};
4219
Matt2f2f4252005-04-13 14:45:30 +02004220static int patch_stac922x(struct hda_codec *codec)
4221{
4222 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004223 int err;
Matt2f2f4252005-04-13 14:45:30 +02004224
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004225 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004226 if (spec == NULL)
4227 return -ENOMEM;
4228
4229 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004230 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004231 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004232 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4233 stac922x_models,
4234 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004235 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004236 spec->gpio_mask = spec->gpio_dir = 0x03;
4237 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004238 /* Intel Macs have all same PCI SSID, so we need to check
4239 * codec SSID to distinguish the exact models
4240 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004241 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004242 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004243
4244 case 0x106b0800:
4245 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004246 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004247 case 0x106b0600:
4248 case 0x106b0700:
4249 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004250 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004251 case 0x106b0e00:
4252 case 0x106b0f00:
4253 case 0x106b1600:
4254 case 0x106b1700:
4255 case 0x106b0200:
4256 case 0x106b1e00:
4257 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004258 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004259 case 0x106b1a00:
4260 case 0x00000100:
4261 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004262 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004263 case 0x106b0a00:
4264 case 0x106b2200:
4265 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004266 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004267 default:
4268 spec->board_config = STAC_INTEL_MAC_V3;
4269 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004270 }
4271 }
4272
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004273 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004274 if (spec->board_config < 0) {
4275 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4276 "using BIOS defaults\n");
4277 err = stac92xx_save_bios_config_regs(codec);
4278 if (err < 0) {
4279 stac92xx_free(codec);
4280 return err;
4281 }
4282 spec->pin_configs = spec->bios_pin_configs;
4283 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004284 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4285 stac92xx_set_config_regs(codec);
4286 }
Matt2f2f4252005-04-13 14:45:30 +02004287
Matt2f2f4252005-04-13 14:45:30 +02004288 spec->adc_nids = stac922x_adc_nids;
4289 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004290 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004291 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004292 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004293 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004294
4295 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004296 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004297
4298 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004299
Matt Porter3cc08dc2006-01-23 15:27:49 +01004300 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004301 if (!err) {
4302 if (spec->board_config < 0) {
4303 printk(KERN_WARNING "hda_codec: No auto-config is "
4304 "available, default to model=ref\n");
4305 spec->board_config = STAC_D945_REF;
4306 goto again;
4307 }
4308 err = -EINVAL;
4309 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004310 if (err < 0) {
4311 stac92xx_free(codec);
4312 return err;
4313 }
4314
4315 codec->patch_ops = stac92xx_patch_ops;
4316
Takashi Iwai807a46362007-05-29 19:01:37 +02004317 /* Fix Mux capture level; max to 2 */
4318 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4319 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4320 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4321 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4322 (0 << AC_AMPCAP_MUTE_SHIFT));
4323
Matt Porter3cc08dc2006-01-23 15:27:49 +01004324 return 0;
4325}
4326
4327static int patch_stac927x(struct hda_codec *codec)
4328{
4329 struct sigmatel_spec *spec;
4330 int err;
4331
4332 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4333 if (spec == NULL)
4334 return -ENOMEM;
4335
4336 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004337 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004338 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004339 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4340 stac927x_models,
4341 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004342 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004343 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4344 if (spec->board_config < 0)
4345 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4346 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004347 err = stac92xx_save_bios_config_regs(codec);
4348 if (err < 0) {
4349 stac92xx_free(codec);
4350 return err;
4351 }
4352 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004353 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004354 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4355 stac92xx_set_config_regs(codec);
4356 }
4357
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004358 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004359 spec->adc_nids = stac927x_adc_nids;
4360 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4361 spec->mux_nids = stac927x_mux_nids;
4362 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004363 spec->smux_nids = stac927x_smux_nids;
4364 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004365 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004366 spec->multiout.dac_nids = spec->dac_nids;
4367
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004368 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004369 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004370 case STAC_D965_5ST:
4371 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004372 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004373 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004374 spec->num_dmics = 0;
4375
Tobin Davis93ed1502006-09-01 21:03:12 +02004376 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004377 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004378 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004379 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004380 switch (codec->subsystem_id) {
4381 case 0x10280209:
4382 case 0x1028022e:
4383 /* correct the device field to SPDIF out */
4384 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4385 break;
4386 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004387 /* configure the analog microphone on some laptops */
4388 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004389 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004390 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004391 /* correct the front input jack as a mic */
4392 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4393 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004394 case STAC_DELL_3ST:
4395 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004396 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004397 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004398 spec->dmic_nids = stac927x_dmic_nids;
4399 spec->num_dmics = STAC927X_NUM_DMICS;
4400
Tobin Davis93ed1502006-09-01 21:03:12 +02004401 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004402 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004403 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004404 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004405 break;
4406 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004407 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004408 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004409 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004410 spec->num_dmics = 0;
4411
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004412 spec->init = stac927x_core_init;
4413 spec->mixer = stac927x_mixer;
4414 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004415
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004416 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004417 spec->aloopback_mask = 0x40;
4418 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004419
Matt Porter3cc08dc2006-01-23 15:27:49 +01004420 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004421 if (!err) {
4422 if (spec->board_config < 0) {
4423 printk(KERN_WARNING "hda_codec: No auto-config is "
4424 "available, default to model=ref\n");
4425 spec->board_config = STAC_D965_REF;
4426 goto again;
4427 }
4428 err = -EINVAL;
4429 }
Mattc7d4b2f2005-06-27 14:59:41 +02004430 if (err < 0) {
4431 stac92xx_free(codec);
4432 return err;
4433 }
Matt2f2f4252005-04-13 14:45:30 +02004434
4435 codec->patch_ops = stac92xx_patch_ops;
4436
Takashi Iwai52987652008-01-16 16:09:47 +01004437 /*
4438 * !!FIXME!!
4439 * The STAC927x seem to require fairly long delays for certain
4440 * command sequences. With too short delays (even if the answer
4441 * is set to RIRB properly), it results in the silence output
4442 * on some hardwares like Dell.
4443 *
4444 * The below flag enables the longer delay (see get_response
4445 * in hda_intel.c).
4446 */
4447 codec->bus->needs_damn_long_delay = 1;
4448
Matt2f2f4252005-04-13 14:45:30 +02004449 return 0;
4450}
4451
Matt Porterf3302a52006-07-31 12:49:34 +02004452static int patch_stac9205(struct hda_codec *codec)
4453{
4454 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004455 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004456
4457 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4458 if (spec == NULL)
4459 return -ENOMEM;
4460
4461 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004462 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004463 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004464 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4465 stac9205_models,
4466 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004467 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004468 if (spec->board_config < 0) {
4469 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4470 err = stac92xx_save_bios_config_regs(codec);
4471 if (err < 0) {
4472 stac92xx_free(codec);
4473 return err;
4474 }
4475 spec->pin_configs = spec->bios_pin_configs;
4476 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004477 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4478 stac92xx_set_config_regs(codec);
4479 }
4480
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004481 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004482 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004483 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004484 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004485 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004486 spec->smux_nids = stac9205_smux_nids;
4487 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004488 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004489 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004490 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004491 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004492 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004493
4494 spec->init = stac9205_core_init;
4495 spec->mixer = stac9205_mixer;
4496
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004497 spec->aloopback_mask = 0x40;
4498 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004499 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004500
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004501 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004502 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004503 /* Enable SPDIF in/out */
4504 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4505 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004506
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004507 /* Enable unsol response for GPIO4/Dock HP connection */
4508 snd_hda_codec_write(codec, codec->afg, 0,
4509 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4510 snd_hda_codec_write_cache(codec, codec->afg, 0,
4511 AC_VERB_SET_UNSOLICITED_ENABLE,
4512 (AC_USRSP_EN | STAC_HP_EVENT));
4513
4514 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004515 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004516 spec->gpio_mask = 0x1b;
4517 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004518 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004519 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004520 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004521 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004522 break;
4523 default:
4524 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004525 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004526 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004527 break;
4528 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004529
Matt Porterf3302a52006-07-31 12:49:34 +02004530 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004531 if (!err) {
4532 if (spec->board_config < 0) {
4533 printk(KERN_WARNING "hda_codec: No auto-config is "
4534 "available, default to model=ref\n");
4535 spec->board_config = STAC_9205_REF;
4536 goto again;
4537 }
4538 err = -EINVAL;
4539 }
Matt Porterf3302a52006-07-31 12:49:34 +02004540 if (err < 0) {
4541 stac92xx_free(codec);
4542 return err;
4543 }
4544
4545 codec->patch_ops = stac92xx_patch_ops;
4546
4547 return 0;
4548}
4549
Matt2f2f4252005-04-13 14:45:30 +02004550/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004551 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004552 */
4553
Guillaume Munch99ccc562006-08-16 19:35:12 +02004554/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004555static hda_nid_t vaio_dacs[] = { 0x2 };
4556#define VAIO_HP_DAC 0x5
4557static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4558static hda_nid_t vaio_mux_nids[] = { 0x15 };
4559
4560static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004561 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004562 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004563 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004564 { "Mic Jack", 0x1 },
4565 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004566 { "PCM", 0x3 },
4567 }
4568};
4569
4570static struct hda_verb vaio_init[] = {
4571 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004572 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004573 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4574 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4575 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4576 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004577 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004578 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4579 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4580 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4581 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4582 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4583 {}
4584};
4585
Guillaume Munch6d859062006-08-22 17:15:47 +02004586static struct hda_verb vaio_ar_init[] = {
4587 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4588 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4589 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4590 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4591/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4592 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004593 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004594 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4595 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4596/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4597 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4598 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4599 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4600 {}
4601};
4602
Takashi Iwaidb064e52006-03-16 16:04:58 +01004603/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004604static struct hda_bind_ctls vaio_bind_master_vol = {
4605 .ops = &snd_hda_bind_vol,
4606 .values = {
4607 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4608 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4609 0
4610 },
4611};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004612
4613/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004614static struct hda_bind_ctls vaio_bind_master_sw = {
4615 .ops = &snd_hda_bind_sw,
4616 .values = {
4617 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4618 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4619 0,
4620 },
4621};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004622
4623static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004624 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4625 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004626 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4627 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4628 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4629 {
4630 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4631 .name = "Capture Source",
4632 .count = 1,
4633 .info = stac92xx_mux_enum_info,
4634 .get = stac92xx_mux_enum_get,
4635 .put = stac92xx_mux_enum_put,
4636 },
4637 {}
4638};
4639
Guillaume Munch6d859062006-08-22 17:15:47 +02004640static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004641 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4642 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004643 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4644 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4645 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4646 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4647 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4648 {
4649 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4650 .name = "Capture Source",
4651 .count = 1,
4652 .info = stac92xx_mux_enum_info,
4653 .get = stac92xx_mux_enum_get,
4654 .put = stac92xx_mux_enum_put,
4655 },
4656 {}
4657};
4658
4659static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004660 .build_controls = stac92xx_build_controls,
4661 .build_pcms = stac92xx_build_pcms,
4662 .init = stac92xx_init,
4663 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004664#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004665 .resume = stac92xx_resume,
4666#endif
4667};
4668
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004669static int stac9872_vaio_init(struct hda_codec *codec)
4670{
4671 int err;
4672
4673 err = stac92xx_init(codec);
4674 if (err < 0)
4675 return err;
4676 if (codec->patch_ops.unsol_event)
4677 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4678 return 0;
4679}
4680
4681static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4682{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004683 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004684 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4685 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4686 } else {
4687 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4688 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4689 }
4690}
4691
4692static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4693{
4694 switch (res >> 26) {
4695 case STAC_HP_EVENT:
4696 stac9872_vaio_hp_detect(codec, res);
4697 break;
4698 }
4699}
4700
4701static struct hda_codec_ops stac9872_vaio_patch_ops = {
4702 .build_controls = stac92xx_build_controls,
4703 .build_pcms = stac92xx_build_pcms,
4704 .init = stac9872_vaio_init,
4705 .free = stac92xx_free,
4706 .unsol_event = stac9872_vaio_unsol_event,
4707#ifdef CONFIG_PM
4708 .resume = stac92xx_resume,
4709#endif
4710};
4711
Guillaume Munch6d859062006-08-22 17:15:47 +02004712enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4713 CXD9872RD_VAIO,
4714 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4715 STAC9872AK_VAIO,
4716 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4717 STAC9872K_VAIO,
4718 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004719 CXD9872AKD_VAIO,
4720 STAC_9872_MODELS,
4721};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004722
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004723static const char *stac9872_models[STAC_9872_MODELS] = {
4724 [CXD9872RD_VAIO] = "vaio",
4725 [CXD9872AKD_VAIO] = "vaio-ar",
4726};
4727
4728static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4729 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4730 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4731 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004732 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004733 {}
4734};
4735
Guillaume Munch6d859062006-08-22 17:15:47 +02004736static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004737{
4738 struct sigmatel_spec *spec;
4739 int board_config;
4740
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004741 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4742 stac9872_models,
4743 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004744 if (board_config < 0)
4745 /* unknown config, let generic-parser do its job... */
4746 return snd_hda_parse_generic_codec(codec);
4747
4748 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4749 if (spec == NULL)
4750 return -ENOMEM;
4751
4752 codec->spec = spec;
4753 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004754 case CXD9872RD_VAIO:
4755 case STAC9872AK_VAIO:
4756 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004757 spec->mixer = vaio_mixer;
4758 spec->init = vaio_init;
4759 spec->multiout.max_channels = 2;
4760 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4761 spec->multiout.dac_nids = vaio_dacs;
4762 spec->multiout.hp_nid = VAIO_HP_DAC;
4763 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4764 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004765 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004766 spec->input_mux = &vaio_mux;
4767 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004768 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004769 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004770
4771 case CXD9872AKD_VAIO:
4772 spec->mixer = vaio_ar_mixer;
4773 spec->init = vaio_ar_init;
4774 spec->multiout.max_channels = 2;
4775 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4776 spec->multiout.dac_nids = vaio_dacs;
4777 spec->multiout.hp_nid = VAIO_HP_DAC;
4778 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004779 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004780 spec->adc_nids = vaio_adcs;
4781 spec->input_mux = &vaio_mux;
4782 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004783 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004784 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004785 }
4786
Takashi Iwaidb064e52006-03-16 16:04:58 +01004787 return 0;
4788}
4789
4790
4791/*
Matt2f2f4252005-04-13 14:45:30 +02004792 * patch entries
4793 */
4794struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4795 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4796 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4797 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4798 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4799 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4800 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4801 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004802 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4803 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4804 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4805 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4806 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4807 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004808 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4809 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4810 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4811 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4812 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4813 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4814 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4815 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4816 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4817 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004818 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4819 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4820 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4821 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4822 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4823 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02004824 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
4825 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004826 /* The following does not take into account .id=0x83847661 when subsys =
4827 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4828 * currently not fully supported.
4829 */
4830 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4831 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4832 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004833 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4834 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4835 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4836 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4837 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4838 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4839 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4840 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004841 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004842 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
4843 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004844 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01004845 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4846 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004847 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004848 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4849 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4850 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4851 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4852 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4853 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4854 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4855 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004856 {} /* terminator */
4857};