blob: 1440175e1008a013a531ccd1a61bc184a2773920 [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 Ranostay4fe5195c2008-01-29 15:28:44 +0100141 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200142 unsigned int eapd_mask;
Matthew Ranostay4fe5195c2008-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 Ranostay4fe5195c2008-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 Ranostay0ffa9802008-09-08 11:20:05 -0400238static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
239 0x26, 0,
240};
241
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100242static hda_nid_t stac92hd73xx_adc_nids[2] = {
243 0x1a, 0x1b
244};
245
246#define STAC92HD73XX_NUM_DMICS 2
247static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
248 0x13, 0x14, 0
249};
250
251#define STAC92HD73_DAC_COUNT 5
252static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
253 0x15, 0x16, 0x17, 0x18, 0x19,
254};
255
256static hda_nid_t stac92hd73xx_mux_nids[4] = {
257 0x28, 0x29, 0x2a, 0x2b,
258};
259
260static hda_nid_t stac92hd73xx_dmux_nids[2] = {
261 0x20, 0x21,
262};
263
Matthew Ranostayd9737752008-09-07 12:03:41 +0200264static hda_nid_t stac92hd73xx_smux_nids[2] = {
265 0x22, 0x23,
266};
267
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200268#define STAC92HD83XXX_NUM_DMICS 2
269static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
270 0x11, 0x12, 0
271};
272
273#define STAC92HD81_DAC_COUNT 2
274#define STAC92HD83_DAC_COUNT 3
275static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
276 0x13, 0x14, 0x22,
277};
278
279static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
280 0x17, 0x18,
281};
282
283static hda_nid_t stac92hd83xxx_adc_nids[2] = {
284 0x15, 0x16,
285};
286
287static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
288 0xa, 0xb, 0xd, 0xe,
289};
290
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400291static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
292 0x1e, 0,
293};
294
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200295static unsigned int stac92hd83xxx_pwr_mapping[4] = {
296 0x03, 0x0c, 0x10, 0x40,
297};
298
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100299static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
300 0x0a, 0x0d, 0x0f
301};
302
Matthew Ranostaye035b842007-11-06 11:53:55 +0100303static hda_nid_t stac92hd71bxx_adc_nids[2] = {
304 0x12, 0x13,
305};
306
307static hda_nid_t stac92hd71bxx_mux_nids[2] = {
308 0x1a, 0x1b
309};
310
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100311static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
312 0x1c,
313};
314
Matthew Ranostayd9737752008-09-07 12:03:41 +0200315static hda_nid_t stac92hd71bxx_smux_nids[2] = {
316 0x24, 0x25,
317};
318
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100319static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100320 0x10, /*0x11, */
321};
322
323#define STAC92HD71BXX_NUM_DMICS 2
324static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
325 0x18, 0x19, 0
326};
327
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400328static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
329 0x22, 0
330};
331
Tobin Davis8e21c342007-01-08 11:04:17 +0100332static hda_nid_t stac925x_adc_nids[1] = {
333 0x03,
334};
335
336static hda_nid_t stac925x_mux_nids[1] = {
337 0x0f,
338};
339
340static hda_nid_t stac925x_dac_nids[1] = {
341 0x02,
342};
343
Takashi Iwaif6e98522007-10-16 14:27:04 +0200344#define STAC925X_NUM_DMICS 1
345static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
346 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200347};
348
Takashi Iwai1697055e2007-12-18 18:05:52 +0100349static hda_nid_t stac925x_dmux_nids[1] = {
350 0x14,
351};
352
Matt2f2f4252005-04-13 14:45:30 +0200353static hda_nid_t stac922x_adc_nids[2] = {
354 0x06, 0x07,
355};
356
357static hda_nid_t stac922x_mux_nids[2] = {
358 0x12, 0x13,
359};
360
Matt Porter3cc08dc2006-01-23 15:27:49 +0100361static hda_nid_t stac927x_adc_nids[3] = {
362 0x07, 0x08, 0x09
363};
364
365static hda_nid_t stac927x_mux_nids[3] = {
366 0x15, 0x16, 0x17
367};
368
Matthew Ranostayd9737752008-09-07 12:03:41 +0200369static hda_nid_t stac927x_smux_nids[1] = {
370 0x21,
371};
372
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100373static hda_nid_t stac927x_dac_nids[6] = {
374 0x02, 0x03, 0x04, 0x05, 0x06, 0
375};
376
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100377static hda_nid_t stac927x_dmux_nids[1] = {
378 0x1b,
379};
380
Matthew Ranostay7f168592007-10-18 17:38:17 +0200381#define STAC927X_NUM_DMICS 2
382static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
383 0x13, 0x14, 0
384};
385
Matt Porterf3302a52006-07-31 12:49:34 +0200386static hda_nid_t stac9205_adc_nids[2] = {
387 0x12, 0x13
388};
389
390static hda_nid_t stac9205_mux_nids[2] = {
391 0x19, 0x1a
392};
393
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100394static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100395 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100396};
397
Matthew Ranostayd9737752008-09-07 12:03:41 +0200398static hda_nid_t stac9205_smux_nids[1] = {
399 0x21,
400};
401
Takashi Iwaif6e98522007-10-16 14:27:04 +0200402#define STAC9205_NUM_DMICS 2
403static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
404 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200405};
406
Mattc7d4b2f2005-06-27 14:59:41 +0200407static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200408 0x08, 0x09, 0x0d, 0x0e,
409 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200410};
411
Tobin Davis8e21c342007-01-08 11:04:17 +0100412static hda_nid_t stac925x_pin_nids[8] = {
413 0x07, 0x08, 0x0a, 0x0b,
414 0x0c, 0x0d, 0x10, 0x11,
415};
416
Matt2f2f4252005-04-13 14:45:30 +0200417static hda_nid_t stac922x_pin_nids[10] = {
418 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
419 0x0f, 0x10, 0x11, 0x15, 0x1b,
420};
421
Matthew Ranostaya7662642008-02-21 07:51:14 +0100422static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100423 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
424 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200425 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100426};
427
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200428static hda_nid_t stac92hd83xxx_pin_nids[14] = {
429 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
430 0x0f, 0x10, 0x11, 0x12, 0x13,
431 0x1d, 0x1e, 0x1f, 0x20
432};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400433static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100434 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
435 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400436 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100437};
438
Matt Porter3cc08dc2006-01-23 15:27:49 +0100439static hda_nid_t stac927x_pin_nids[14] = {
440 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
441 0x0f, 0x10, 0x11, 0x12, 0x13,
442 0x14, 0x21, 0x22, 0x23,
443};
444
Matt Porterf3302a52006-07-31 12:49:34 +0200445static hda_nid_t stac9205_pin_nids[12] = {
446 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
447 0x0f, 0x14, 0x16, 0x17, 0x18,
448 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200449};
450
Matt Porter8b657272006-10-26 17:12:59 +0200451static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_info *uinfo)
453{
454 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
455 struct sigmatel_spec *spec = codec->spec;
456 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
457}
458
459static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
460 struct snd_ctl_elem_value *ucontrol)
461{
462 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
463 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100464 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200465
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100466 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200467 return 0;
468}
469
470static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
471 struct snd_ctl_elem_value *ucontrol)
472{
473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
474 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100475 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200476
477 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100478 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200479}
480
Matthew Ranostayd9737752008-09-07 12:03:41 +0200481static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
482 struct snd_ctl_elem_info *uinfo)
483{
484 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
485 struct sigmatel_spec *spec = codec->spec;
486 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
487}
488
489static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_value *ucontrol)
491{
492 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
493 struct sigmatel_spec *spec = codec->spec;
494 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
495
496 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
497 return 0;
498}
499
500static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
501 struct snd_ctl_elem_value *ucontrol)
502{
503 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
504 struct sigmatel_spec *spec = codec->spec;
505 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
506
507 return snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
508 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
509}
510
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100511static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200512{
513 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
514 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200515 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200516}
517
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100518static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200519{
520 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
521 struct sigmatel_spec *spec = codec->spec;
522 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
523
524 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
525 return 0;
526}
527
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100528static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200529{
530 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
531 struct sigmatel_spec *spec = codec->spec;
532 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
533
Mattc7d4b2f2005-06-27 14:59:41 +0200534 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200535 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
536}
537
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100538static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_info *uinfo)
540{
541 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
542 struct sigmatel_spec *spec = codec->spec;
543 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
544}
545
546static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
547 struct snd_ctl_elem_value *ucontrol)
548{
549 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
550 struct sigmatel_spec *spec = codec->spec;
551
552 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
553 return 0;
554}
555
556static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
557 struct snd_ctl_elem_value *ucontrol)
558{
559 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
560 struct sigmatel_spec *spec = codec->spec;
561
562 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
563 spec->mono_nid, &spec->cur_mmux);
564}
565
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200566#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
567
568static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
569 struct snd_ctl_elem_value *ucontrol)
570{
571 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
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 struct sigmatel_spec *spec = codec->spec;
574
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100575 ucontrol->value.integer.value[0] = !!(spec->aloopback &
576 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200577 return 0;
578}
579
580static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
581 struct snd_ctl_elem_value *ucontrol)
582{
583 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
584 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100585 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200586 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100587 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200588
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100589 idx_val = spec->aloopback_mask << idx;
590 if (ucontrol->value.integer.value[0])
591 val = spec->aloopback | idx_val;
592 else
593 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100594 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200595 return 0;
596
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100597 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200598
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100599 /* Only return the bits defined by the shift value of the
600 * first two bytes of the mask
601 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200602 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100603 kcontrol->private_value & 0xFFFF, 0x0);
604 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200605
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100606 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200607 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100608 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200609 } else {
610 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100611 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200612 }
613
614 snd_hda_codec_write_cache(codec, codec->afg, 0,
615 kcontrol->private_value >> 16, dac_mode);
616
617 return 1;
618}
619
Mattc7d4b2f2005-06-27 14:59:41 +0200620static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200621 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200622 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200623 {}
624};
625
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200626static struct hda_verb stac9200_eapd_init[] = {
627 /* set dac0mux for dac converter */
628 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
629 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
630 {}
631};
632
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100633static struct hda_verb stac92hd73xx_6ch_core_init[] = {
634 /* set master volume and direct control */
635 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
636 /* setup audio connections */
637 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
638 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
639 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
640 /* setup adcs to point to mixer */
641 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
642 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100643 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
644 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
645 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
646 /* setup import muxs */
647 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
648 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
649 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
650 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
651 {}
652};
653
Matthew Ranostayd654a662008-03-14 08:46:51 +0100654static struct hda_verb dell_eq_core_init[] = {
655 /* set master volume to max value without distortion
656 * and direct control */
657 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
658 /* setup audio connections */
659 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
660 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
661 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
662 /* setup adcs to point to mixer */
663 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
664 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
665 /* setup import muxs */
666 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
667 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
668 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
669 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
670 {}
671};
672
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100673static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay20f5f952008-09-01 08:17:56 +0200674 /* set master volume to max value without distortion
675 * and direct control */
676 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100677 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100678 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
679 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100680 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
681 /* setup adcs to point to mixer */
682 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
683 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
684 /* setup import muxs */
685 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
686 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
687 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
688 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
689 {}
690};
691
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692static struct hda_verb stac92hd73xx_8ch_core_init[] = {
693 /* set master volume and direct control */
694 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
695 /* setup audio connections */
696 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
697 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
698 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
699 /* connect hp ports to dac3 */
700 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
701 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
702 /* setup adcs to point to mixer */
703 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
704 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100705 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
706 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
707 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
708 /* setup import muxs */
709 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
710 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
711 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
712 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
713 {}
714};
715
716static struct hda_verb stac92hd73xx_10ch_core_init[] = {
717 /* set master volume and direct control */
718 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
719 /* setup audio connections */
720 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
721 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
722 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
723 /* dac3 is connected to import3 mux */
724 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
725 /* connect hp ports to dac4 */
726 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
727 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
728 /* setup adcs to point to mixer */
729 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
730 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100731 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
732 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
733 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
734 /* setup import muxs */
735 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
736 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
737 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
738 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
739 {}
740};
741
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200742static struct hda_verb stac92hd83xxx_core_init[] = {
743 /* start of config #1 */
744 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
745
746 /* start of config #2 */
747 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
748 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
749 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
750
751 /* power state controls amps */
752 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
753};
754
Matthew Ranostaye035b842007-11-06 11:53:55 +0100755static struct hda_verb stac92hd71bxx_core_init[] = {
756 /* set master volume and direct control */
757 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
758 /* connect headphone jack to dac1 */
759 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100760 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
761 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
762 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
763 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
764 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100765};
766
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200767#define HD_DISABLE_PORTF 3
Matthew Ranostay541eee82007-12-14 12:08:04 +0100768static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200769 /* start of config #1 */
770
771 /* connect port 0f to audio mixer */
772 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
773 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
774 /* unmute right and left channels for node 0x0f */
775 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
776 /* start of config #2 */
777
Matthew Ranostay541eee82007-12-14 12:08:04 +0100778 /* set master volume and direct control */
779 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
780 /* connect headphone jack to dac1 */
781 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200782 /* connect port 0d to audio mixer */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100783 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100784 /* unmute dac0 input in audio mixer */
785 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200786 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100787 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
788 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100789 {}
790};
791
Tobin Davis8e21c342007-01-08 11:04:17 +0100792static struct hda_verb stac925x_core_init[] = {
793 /* set dac0mux for dac converter */
794 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
795 {}
796};
797
Mattc7d4b2f2005-06-27 14:59:41 +0200798static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200799 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200800 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200801 {}
802};
803
Tobin Davis93ed1502006-09-01 21:03:12 +0200804static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200805 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200806 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200807 /* unmute node 0x1b */
808 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
809 /* select node 0x03 as DAC */
810 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
811 {}
812};
813
Matt Porter3cc08dc2006-01-23 15:27:49 +0100814static struct hda_verb stac927x_core_init[] = {
815 /* set master volume and direct control */
816 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200817 /* enable analog pc beep path */
818 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100819 {}
820};
821
Matt Porterf3302a52006-07-31 12:49:34 +0200822static struct hda_verb stac9205_core_init[] = {
823 /* set master volume and direct control */
824 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200825 /* enable analog pc beep path */
826 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200827 {}
828};
829
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100830#define STAC_MONO_MUX \
831 { \
832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
833 .name = "Mono Mux", \
834 .count = 1, \
835 .info = stac92xx_mono_mux_enum_info, \
836 .get = stac92xx_mono_mux_enum_get, \
837 .put = stac92xx_mono_mux_enum_put, \
838 }
839
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200840#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200841 { \
842 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
843 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200844 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200845 .info = stac92xx_mux_enum_info, \
846 .get = stac92xx_mux_enum_get, \
847 .put = stac92xx_mux_enum_put, \
848 }
849
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100850#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200851 { \
852 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
853 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100854 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200855 .info = stac92xx_aloopback_info, \
856 .get = stac92xx_aloopback_get, \
857 .put = stac92xx_aloopback_put, \
858 .private_value = verb_read | (verb_write << 16), \
859 }
860
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100861static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200862 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
863 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200864 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200865 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
866 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200867 { } /* end */
868};
869
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100870static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100871 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
872
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100873 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
874 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
875
876 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
877 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
878
879 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
880 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
881
882 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
883 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
884
885 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
886 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
887
888 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
889 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
890
891 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
892 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
893 { } /* end */
894};
895
896static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100897 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
898
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100899 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
900 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
901
902 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
903 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
904
905 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
906 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
907
908 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
909 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
910
911 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
912 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
913
914 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
915 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
916
917 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
918 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
919 { } /* end */
920};
921
922static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100923 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
924
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100925 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
926 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
927
928 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
929 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
930
931 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
932 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
933
934 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
935 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
936
937 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
938 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
939
940 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
941 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
942
943 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
944 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
945 { } /* end */
946};
947
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200948
949static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
950 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
951 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
952
953 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
954 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
955
956 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
957 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
958
959 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
960 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
961
962 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
963 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
964
965 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
966 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
967
968 /*
969 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
970 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
971 */
972 { } /* end */
973};
974
Matthew Ranostay541eee82007-12-14 12:08:04 +0100975static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100976 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100977
Matthew Ranostay9b359472007-11-07 13:03:12 +0100978 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
979 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +0100980
981 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
982 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200983 /* analog pc-beep replaced with digital beep support */
984 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200985 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
986 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200987 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200988
Matthew Ranostay9b359472007-11-07 13:03:12 +0100989 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
990 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100991 { } /* end */
992};
993
Matthew Ranostay541eee82007-12-14 12:08:04 +0100994static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100995 STAC_INPUT_SOURCE(2),
996 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
997
Matthew Ranostay541eee82007-12-14 12:08:04 +0100998 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
999 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001000
1001 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1002 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001003 { } /* end */
1004};
1005
Tobin Davis8e21c342007-01-08 11:04:17 +01001006static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001007 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001008 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001009 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001010 { } /* end */
1011};
1012
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001013static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001014 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001015 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001016
1017 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1018 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001019
1020 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1021 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001022 { } /* end */
1023};
1024
1025/* This needs to be generated dynamically based on sequence */
1026static struct snd_kcontrol_new stac922x_mixer[] = {
1027 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001028 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1029 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001030
1031 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1032 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001033 { } /* end */
1034};
1035
1036
1037static struct snd_kcontrol_new stac927x_mixer[] = {
1038 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001039 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001040
1041 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1042 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001043
1044 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1045 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001046
1047 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1048 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001049 { } /* end */
1050};
1051
Takashi Iwai1697055e2007-12-18 18:05:52 +01001052static struct snd_kcontrol_new stac_dmux_mixer = {
1053 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1054 .name = "Digital Input Source",
1055 /* count set later */
1056 .info = stac92xx_dmux_enum_info,
1057 .get = stac92xx_dmux_enum_get,
1058 .put = stac92xx_dmux_enum_put,
1059};
1060
Matthew Ranostayd9737752008-09-07 12:03:41 +02001061static struct snd_kcontrol_new stac_smux_mixer = {
1062 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1063 .name = "IEC958 Mux",
1064 /* count set later */
1065 .info = stac92xx_smux_enum_info,
1066 .get = stac92xx_smux_enum_get,
1067 .put = stac92xx_smux_enum_put,
1068};
1069
Takashi Iwai2134ea42008-01-10 16:53:55 +01001070static const char *slave_vols[] = {
1071 "Front Playback Volume",
1072 "Surround Playback Volume",
1073 "Center Playback Volume",
1074 "LFE Playback Volume",
1075 "Side Playback Volume",
1076 "Headphone Playback Volume",
1077 "Headphone Playback Volume",
1078 "Speaker Playback Volume",
1079 "External Speaker Playback Volume",
1080 "Speaker2 Playback Volume",
1081 NULL
1082};
1083
1084static const char *slave_sws[] = {
1085 "Front Playback Switch",
1086 "Surround Playback Switch",
1087 "Center Playback Switch",
1088 "LFE Playback Switch",
1089 "Side Playback Switch",
1090 "Headphone Playback Switch",
1091 "Headphone Playback Switch",
1092 "Speaker Playback Switch",
1093 "External Speaker Playback Switch",
1094 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001095 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001096 NULL
1097};
1098
Matt2f2f4252005-04-13 14:45:30 +02001099static int stac92xx_build_controls(struct hda_codec *codec)
1100{
1101 struct sigmatel_spec *spec = codec->spec;
1102 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001103 int i;
Matt2f2f4252005-04-13 14:45:30 +02001104
1105 err = snd_hda_add_new_ctls(codec, spec->mixer);
1106 if (err < 0)
1107 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001108
1109 for (i = 0; i < spec->num_mixers; i++) {
1110 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1111 if (err < 0)
1112 return err;
1113 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001114 if (spec->num_dmuxes > 0) {
1115 stac_dmux_mixer.count = spec->num_dmuxes;
1116 err = snd_ctl_add(codec->bus->card,
1117 snd_ctl_new1(&stac_dmux_mixer, codec));
1118 if (err < 0)
1119 return err;
1120 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001121 if (spec->num_smuxes > 0) {
1122 stac_smux_mixer.count = spec->num_smuxes;
1123 err = snd_ctl_add(codec->bus->card,
1124 snd_ctl_new1(&stac_smux_mixer, codec));
1125 if (err < 0)
1126 return err;
1127 }
Mattc7d4b2f2005-06-27 14:59:41 +02001128
Mattdabbed62005-06-14 10:19:34 +02001129 if (spec->multiout.dig_out_nid) {
1130 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1131 if (err < 0)
1132 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001133 err = snd_hda_create_spdif_share_sw(codec,
1134 &spec->multiout);
1135 if (err < 0)
1136 return err;
1137 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001138 }
1139 if (spec->dig_in_nid) {
1140 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1141 if (err < 0)
1142 return err;
1143 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001144
1145 /* if we have no master control, let's create it */
1146 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001147 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001148 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001149 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001150 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001151 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001152 if (err < 0)
1153 return err;
1154 }
1155 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1156 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1157 NULL, slave_sws);
1158 if (err < 0)
1159 return err;
1160 }
1161
Mattdabbed62005-06-14 10:19:34 +02001162 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001163}
1164
Matt Porter403d1942005-11-29 15:00:51 +01001165static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001166 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001167 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1168};
1169
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001170/*
1171 STAC 9200 pin configs for
1172 102801A8
1173 102801DE
1174 102801E8
1175*/
1176static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001177 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1178 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001179};
1180
1181/*
1182 STAC 9200 pin configs for
1183 102801C0
1184 102801C1
1185*/
1186static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001187 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1188 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001189};
1190
1191/*
1192 STAC 9200 pin configs for
1193 102801C4 (Dell Dimension E310)
1194 102801C5
1195 102801C7
1196 102801D9
1197 102801DA
1198 102801E3
1199*/
1200static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001201 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1202 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001203};
1204
1205
1206/*
1207 STAC 9200-32 pin configs for
1208 102801B5 (Dell Inspiron 630m)
1209 102801D8 (Dell Inspiron 640m)
1210*/
1211static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001212 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1213 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001214};
1215
1216/*
1217 STAC 9200-32 pin configs for
1218 102801C2 (Dell Latitude D620)
1219 102801C8
1220 102801CC (Dell Latitude D820)
1221 102801D4
1222 102801D6
1223*/
1224static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001225 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1226 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001227};
1228
1229/*
1230 STAC 9200-32 pin configs for
1231 102801CE (Dell XPS M1710)
1232 102801CF (Dell Precision M90)
1233*/
1234static unsigned int dell9200_m23_pin_configs[8] = {
1235 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1236 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1237};
1238
1239/*
1240 STAC 9200-32 pin configs for
1241 102801C9
1242 102801CA
1243 102801CB (Dell Latitude 120L)
1244 102801D3
1245*/
1246static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001247 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1248 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001249};
1250
1251/*
1252 STAC 9200-32 pin configs for
1253 102801BD (Dell Inspiron E1505n)
1254 102801EE
1255 102801EF
1256*/
1257static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001258 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1259 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001260};
1261
1262/*
1263 STAC 9200-32 pin configs for
1264 102801F5 (Dell Inspiron 1501)
1265 102801F6
1266*/
1267static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001268 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1269 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001270};
1271
1272/*
1273 STAC 9200-32
1274 102801CD (Dell Inspiron E1705/9400)
1275*/
1276static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001277 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1278 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001279};
1280
Tobin Davisbf277782008-02-03 20:31:47 +01001281static unsigned int oqo9200_pin_configs[8] = {
1282 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1283 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1284};
1285
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001286
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001287static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1288 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001289 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001290 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1291 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1292 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1293 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1294 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1295 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1296 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1297 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1298 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1299 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001300 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001301};
1302
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001303static const char *stac9200_models[STAC_9200_MODELS] = {
1304 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001305 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001306 [STAC_9200_DELL_D21] = "dell-d21",
1307 [STAC_9200_DELL_D22] = "dell-d22",
1308 [STAC_9200_DELL_D23] = "dell-d23",
1309 [STAC_9200_DELL_M21] = "dell-m21",
1310 [STAC_9200_DELL_M22] = "dell-m22",
1311 [STAC_9200_DELL_M23] = "dell-m23",
1312 [STAC_9200_DELL_M24] = "dell-m24",
1313 [STAC_9200_DELL_M25] = "dell-m25",
1314 [STAC_9200_DELL_M26] = "dell-m26",
1315 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001316 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001317 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001318};
1319
1320static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1321 /* SigmaTel reference board */
1322 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1323 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001324 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001325 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1326 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001327 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001328 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1329 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1330 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1331 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1332 "unknown Dell", STAC_9200_DELL_D22),
1333 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1334 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001335 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001336 "Dell Latitude D620", STAC_9200_DELL_M22),
1337 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1338 "unknown Dell", STAC_9200_DELL_D23),
1339 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1340 "unknown Dell", STAC_9200_DELL_D23),
1341 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1342 "unknown Dell", STAC_9200_DELL_M22),
1343 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1344 "unknown Dell", STAC_9200_DELL_M24),
1345 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1346 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001347 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001348 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001349 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001350 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001351 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001352 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001353 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001354 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001355 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001356 "Dell Precision M90", STAC_9200_DELL_M23),
1357 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1358 "unknown Dell", STAC_9200_DELL_M22),
1359 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1360 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001361 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001362 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001363 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001364 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1365 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1366 "unknown Dell", STAC_9200_DELL_D23),
1367 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1368 "unknown Dell", STAC_9200_DELL_D23),
1369 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1370 "unknown Dell", STAC_9200_DELL_D21),
1371 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1372 "unknown Dell", STAC_9200_DELL_D23),
1373 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1374 "unknown Dell", STAC_9200_DELL_D21),
1375 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1376 "unknown Dell", STAC_9200_DELL_M25),
1377 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1378 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001379 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001380 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1381 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1382 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001383 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001384 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001385 /* Gateway machines needs EAPD to be set on resume */
1386 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1387 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1388 STAC_9200_GATEWAY),
1389 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1390 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001391 /* OQO Mobile */
1392 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001393 {} /* terminator */
1394};
1395
Tobin Davis8e21c342007-01-08 11:04:17 +01001396static unsigned int ref925x_pin_configs[8] = {
1397 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001398 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001399};
1400
1401static unsigned int stac925x_MA6_pin_configs[8] = {
1402 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1403 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1404};
1405
Tobin Davis2c11f952007-05-17 09:36:34 +02001406static unsigned int stac925x_PA6_pin_configs[8] = {
1407 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1408 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1409};
1410
Tobin Davis8e21c342007-01-08 11:04:17 +01001411static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001412 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1413 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001414};
1415
1416static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1417 [STAC_REF] = ref925x_pin_configs,
1418 [STAC_M2_2] = stac925xM2_2_pin_configs,
1419 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001420 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001421};
1422
1423static const char *stac925x_models[STAC_925x_MODELS] = {
1424 [STAC_REF] = "ref",
1425 [STAC_M2_2] = "m2-2",
1426 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001427 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001428};
1429
1430static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1431 /* SigmaTel reference board */
1432 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001433 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001434 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1435 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1436 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001437 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001438 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1439 {} /* terminator */
1440};
1441
Matthew Ranostaya7662642008-02-21 07:51:14 +01001442static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001443 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1444 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1445 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001446 0x01452050,
1447};
1448
1449static unsigned int dell_m6_pin_configs[13] = {
1450 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001451 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001452 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1453 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001454};
1455
1456static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001457 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1458 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001459};
1460
1461static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1462 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001463 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001464};
1465
1466static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1467 /* SigmaTel reference board */
1468 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001469 "DFI LanParty", STAC_92HD73XX_REF),
1470 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1471 "unknown Dell", STAC_DELL_M6),
1472 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1473 "unknown Dell", STAC_DELL_M6),
1474 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1475 "unknown Dell", STAC_DELL_M6),
1476 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1477 "unknown Dell", STAC_DELL_M6),
1478 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1479 "unknown Dell", STAC_DELL_M6),
1480 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1481 "unknown Dell", STAC_DELL_M6),
1482 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1483 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001484 {} /* terminator */
1485};
1486
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001487static unsigned int ref92hd83xxx_pin_configs[14] = {
1488 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1489 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1490 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1491 0x01451160, 0x98560170,
1492};
1493
1494static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1495 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1496};
1497
1498static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1499 [STAC_92HD83XXX_REF] = "ref",
1500};
1501
1502static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1503 /* SigmaTel reference board */
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1505 "DFI LanParty", STAC_92HD71BXX_REF),
1506};
1507
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001508static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001509 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001510 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001511 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001512};
1513
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001514static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001515 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001516 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001517 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001518};
1519
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001520static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001521 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1522 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001523 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001524};
1525
Matthew Ranostaye035b842007-11-06 11:53:55 +01001526static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1527 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001528 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1529 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001530};
1531
1532static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1533 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001534 [STAC_DELL_M4_1] = "dell-m4-1",
1535 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001536};
1537
1538static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1539 /* SigmaTel reference board */
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1541 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1543 "unknown Dell", STAC_DELL_M4_1),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1545 "unknown Dell", STAC_DELL_M4_1),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1547 "unknown Dell", STAC_DELL_M4_1),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1549 "unknown Dell", STAC_DELL_M4_1),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1551 "unknown Dell", STAC_DELL_M4_1),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1553 "unknown Dell", STAC_DELL_M4_1),
1554 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1555 "unknown Dell", STAC_DELL_M4_1),
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1557 "unknown Dell", STAC_DELL_M4_2),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1559 "unknown Dell", STAC_DELL_M4_2),
1560 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1561 "unknown Dell", STAC_DELL_M4_2),
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1563 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001564 {} /* terminator */
1565};
1566
Matt Porter403d1942005-11-29 15:00:51 +01001567static unsigned int ref922x_pin_configs[10] = {
1568 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1569 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001570 0x40000100, 0x40000100,
1571};
1572
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001573/*
1574 STAC 922X pin configs for
1575 102801A7
1576 102801AB
1577 102801A9
1578 102801D1
1579 102801D2
1580*/
1581static unsigned int dell_922x_d81_pin_configs[10] = {
1582 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1583 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1584 0x01813122, 0x400001f2,
1585};
1586
1587/*
1588 STAC 922X pin configs for
1589 102801AC
1590 102801D0
1591*/
1592static unsigned int dell_922x_d82_pin_configs[10] = {
1593 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1594 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1595 0x01813122, 0x400001f1,
1596};
1597
1598/*
1599 STAC 922X pin configs for
1600 102801BF
1601*/
1602static unsigned int dell_922x_m81_pin_configs[10] = {
1603 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1604 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1605 0x40C003f1, 0x405003f0,
1606};
1607
1608/*
1609 STAC 9221 A1 pin configs for
1610 102801D7 (Dell XPS M1210)
1611*/
1612static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001613 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1614 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001615 0x508003f3, 0x405003f4,
1616};
1617
Matt Porter403d1942005-11-29 15:00:51 +01001618static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001619 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001620 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1621 0x02a19120, 0x40000100,
1622};
1623
1624static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001625 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1626 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001627 0x02a19320, 0x40000100,
1628};
1629
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001630static unsigned int intel_mac_v1_pin_configs[10] = {
1631 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1632 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001633 0x400000fc, 0x400000fb,
1634};
1635
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001636static unsigned int intel_mac_v2_pin_configs[10] = {
1637 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1638 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001639 0x400000fc, 0x400000fb,
1640};
1641
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001642static unsigned int intel_mac_v3_pin_configs[10] = {
1643 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1644 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1645 0x400000fc, 0x400000fb,
1646};
1647
1648static unsigned int intel_mac_v4_pin_configs[10] = {
1649 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1650 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1651 0x400000fc, 0x400000fb,
1652};
1653
1654static unsigned int intel_mac_v5_pin_configs[10] = {
1655 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1656 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1657 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001658};
1659
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001660static unsigned int ecs202_pin_configs[10] = {
1661 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1662 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1663 0x9037012e, 0x40e000f2,
1664};
Takashi Iwai76c08822007-06-19 12:17:42 +02001665
Takashi Iwai19039bd2006-06-28 15:52:16 +02001666static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001667 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001668 [STAC_D945GTP3] = d945gtp3_pin_configs,
1669 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001670 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1671 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1672 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1673 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1674 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001675 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001676 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001677 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1678 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1679 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1680 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1681 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1682 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001683 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001684 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1685 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1686 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1687 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001688};
1689
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001690static const char *stac922x_models[STAC_922X_MODELS] = {
1691 [STAC_D945_REF] = "ref",
1692 [STAC_D945GTP5] = "5stack",
1693 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001694 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1695 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1696 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1697 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1698 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001699 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001700 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001701 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001702 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001703 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1704 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001705 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001706 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001707 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001708 [STAC_922X_DELL_D81] = "dell-d81",
1709 [STAC_922X_DELL_D82] = "dell-d82",
1710 [STAC_922X_DELL_M81] = "dell-m81",
1711 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001712};
1713
1714static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1715 /* SigmaTel reference board */
1716 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1717 "DFI LanParty", STAC_D945_REF),
1718 /* Intel 945G based systems */
1719 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1720 "Intel D945G", STAC_D945GTP3),
1721 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1722 "Intel D945G", STAC_D945GTP3),
1723 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1724 "Intel D945G", STAC_D945GTP3),
1725 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1726 "Intel D945G", STAC_D945GTP3),
1727 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1728 "Intel D945G", STAC_D945GTP3),
1729 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1730 "Intel D945G", STAC_D945GTP3),
1731 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1732 "Intel D945G", STAC_D945GTP3),
1733 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1734 "Intel D945G", STAC_D945GTP3),
1735 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1736 "Intel D945G", STAC_D945GTP3),
1737 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1738 "Intel D945G", STAC_D945GTP3),
1739 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1740 "Intel D945G", STAC_D945GTP3),
1741 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1742 "Intel D945G", STAC_D945GTP3),
1743 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1744 "Intel D945G", STAC_D945GTP3),
1745 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1746 "Intel D945G", STAC_D945GTP3),
1747 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1748 "Intel D945G", STAC_D945GTP3),
1749 /* Intel D945G 5-stack systems */
1750 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1751 "Intel D945G", STAC_D945GTP5),
1752 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1753 "Intel D945G", STAC_D945GTP5),
1754 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1755 "Intel D945G", STAC_D945GTP5),
1756 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1757 "Intel D945G", STAC_D945GTP5),
1758 /* Intel 945P based systems */
1759 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1760 "Intel D945P", STAC_D945GTP3),
1761 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1762 "Intel D945P", STAC_D945GTP3),
1763 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1764 "Intel D945P", STAC_D945GTP3),
1765 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1766 "Intel D945P", STAC_D945GTP3),
1767 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1768 "Intel D945P", STAC_D945GTP3),
1769 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1770 "Intel D945P", STAC_D945GTP5),
1771 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001772 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001773 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001774 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001775 /* Dell systems */
1776 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1777 "unknown Dell", STAC_922X_DELL_D81),
1778 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1779 "unknown Dell", STAC_922X_DELL_D81),
1780 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1781 "unknown Dell", STAC_922X_DELL_D81),
1782 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1783 "unknown Dell", STAC_922X_DELL_D82),
1784 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1785 "unknown Dell", STAC_922X_DELL_M81),
1786 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1787 "unknown Dell", STAC_922X_DELL_D82),
1788 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1789 "unknown Dell", STAC_922X_DELL_D81),
1790 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1791 "unknown Dell", STAC_922X_DELL_D81),
1792 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1793 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001794 /* ECS/PC Chips boards */
1795 SND_PCI_QUIRK(0x1019, 0x2144,
1796 "ECS/PC chips", STAC_ECS_202),
1797 SND_PCI_QUIRK(0x1019, 0x2608,
1798 "ECS/PC chips", STAC_ECS_202),
1799 SND_PCI_QUIRK(0x1019, 0x2633,
1800 "ECS/PC chips P17G/1333", STAC_ECS_202),
1801 SND_PCI_QUIRK(0x1019, 0x2811,
1802 "ECS/PC chips", STAC_ECS_202),
1803 SND_PCI_QUIRK(0x1019, 0x2812,
1804 "ECS/PC chips", STAC_ECS_202),
1805 SND_PCI_QUIRK(0x1019, 0x2813,
1806 "ECS/PC chips", STAC_ECS_202),
1807 SND_PCI_QUIRK(0x1019, 0x2814,
1808 "ECS/PC chips", STAC_ECS_202),
1809 SND_PCI_QUIRK(0x1019, 0x2815,
1810 "ECS/PC chips", STAC_ECS_202),
1811 SND_PCI_QUIRK(0x1019, 0x2816,
1812 "ECS/PC chips", STAC_ECS_202),
1813 SND_PCI_QUIRK(0x1019, 0x2817,
1814 "ECS/PC chips", STAC_ECS_202),
1815 SND_PCI_QUIRK(0x1019, 0x2818,
1816 "ECS/PC chips", STAC_ECS_202),
1817 SND_PCI_QUIRK(0x1019, 0x2819,
1818 "ECS/PC chips", STAC_ECS_202),
1819 SND_PCI_QUIRK(0x1019, 0x2820,
1820 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001821 {} /* terminator */
1822};
1823
Matt Porter3cc08dc2006-01-23 15:27:49 +01001824static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001825 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1826 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1827 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1828 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001829};
1830
Tobin Davis93ed1502006-09-01 21:03:12 +02001831static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001832 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1833 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1834 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1835 0x40000100, 0x40000100
1836};
1837
Tobin Davis93ed1502006-09-01 21:03:12 +02001838static unsigned int d965_5st_pin_configs[14] = {
1839 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1840 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1841 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1842 0x40000100, 0x40000100
1843};
1844
Tobin Davis4ff076e2007-08-07 11:48:12 +02001845static unsigned int dell_3st_pin_configs[14] = {
1846 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1847 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001848 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001849 0x40c003fc, 0x40000100
1850};
1851
Tobin Davis93ed1502006-09-01 21:03:12 +02001852static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001853 [STAC_D965_REF] = ref927x_pin_configs,
1854 [STAC_D965_3ST] = d965_3st_pin_configs,
1855 [STAC_D965_5ST] = d965_5st_pin_configs,
1856 [STAC_DELL_3ST] = dell_3st_pin_configs,
1857 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001858};
1859
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001860static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001861 [STAC_D965_REF] = "ref",
1862 [STAC_D965_3ST] = "3stack",
1863 [STAC_D965_5ST] = "5stack",
1864 [STAC_DELL_3ST] = "dell-3stack",
1865 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001866};
1867
1868static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1869 /* SigmaTel reference board */
1870 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1871 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001872 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001873 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1874 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001875 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001876 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1877 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1878 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1879 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1880 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1881 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1882 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1883 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1884 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1885 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1886 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1887 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1888 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1889 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1890 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1891 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001892 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001893 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001894 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001895 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1896 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001897 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001898 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1899 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001900 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02001901 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001902 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1903 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1904 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1905 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001906 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001907 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1908 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1909 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1910 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1911 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1912 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1913 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1914 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1915 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001916 {} /* terminator */
1917};
1918
Matt Porterf3302a52006-07-31 12:49:34 +02001919static unsigned int ref9205_pin_configs[12] = {
1920 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001921 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001922 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001923};
1924
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001925/*
1926 STAC 9205 pin configs for
1927 102801F1
1928 102801F2
1929 102801FC
1930 102801FD
1931 10280204
1932 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001933 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001934*/
1935static unsigned int dell_9205_m42_pin_configs[12] = {
1936 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1937 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1938 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1939};
1940
1941/*
1942 STAC 9205 pin configs for
1943 102801F9
1944 102801FA
1945 102801FE
1946 102801FF (Dell Precision M4300)
1947 10280206
1948 10280200
1949 10280201
1950*/
1951static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001952 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1953 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1954 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1955};
1956
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001957static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001958 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1959 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1960 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1961};
1962
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001963static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001964 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001965 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1966 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1967 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001968};
1969
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001970static const char *stac9205_models[STAC_9205_MODELS] = {
1971 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001972 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001973 [STAC_9205_DELL_M43] = "dell-m43",
1974 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001975};
1976
1977static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1978 /* SigmaTel reference board */
1979 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1980 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001981 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1982 "unknown Dell", STAC_9205_DELL_M42),
1983 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1984 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001985 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001986 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001987 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1988 "Dell Precision", STAC_9205_DELL_M43),
1989 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1990 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001991 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1992 "unknown Dell", STAC_9205_DELL_M42),
1993 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1994 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001995 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1996 "Dell Precision", STAC_9205_DELL_M43),
1997 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001998 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001999 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2000 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002001 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2002 "Dell Precision", STAC_9205_DELL_M43),
2003 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2004 "Dell Precision", STAC_9205_DELL_M43),
2005 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2006 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002007 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2008 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002009 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2010 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002011 {} /* terminator */
2012};
2013
Richard Fish11b44bb2006-08-23 18:31:34 +02002014static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2015{
2016 int i;
2017 struct sigmatel_spec *spec = codec->spec;
2018
2019 if (! spec->bios_pin_configs) {
2020 spec->bios_pin_configs = kcalloc(spec->num_pins,
2021 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2022 if (! spec->bios_pin_configs)
2023 return -ENOMEM;
2024 }
2025
2026 for (i = 0; i < spec->num_pins; i++) {
2027 hda_nid_t nid = spec->pin_nids[i];
2028 unsigned int pin_cfg;
2029
2030 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2031 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2032 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2033 nid, pin_cfg);
2034 spec->bios_pin_configs[i] = pin_cfg;
2035 }
2036
2037 return 0;
2038}
2039
Matthew Ranostay87d48362007-07-17 11:52:24 +02002040static void stac92xx_set_config_reg(struct hda_codec *codec,
2041 hda_nid_t pin_nid, unsigned int pin_config)
2042{
2043 int i;
2044 snd_hda_codec_write(codec, pin_nid, 0,
2045 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2046 pin_config & 0x000000ff);
2047 snd_hda_codec_write(codec, pin_nid, 0,
2048 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2049 (pin_config & 0x0000ff00) >> 8);
2050 snd_hda_codec_write(codec, pin_nid, 0,
2051 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2052 (pin_config & 0x00ff0000) >> 16);
2053 snd_hda_codec_write(codec, pin_nid, 0,
2054 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2055 pin_config >> 24);
2056 i = snd_hda_codec_read(codec, pin_nid, 0,
2057 AC_VERB_GET_CONFIG_DEFAULT,
2058 0x00);
2059 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2060 pin_nid, i);
2061}
2062
Matt2f2f4252005-04-13 14:45:30 +02002063static void stac92xx_set_config_regs(struct hda_codec *codec)
2064{
2065 int i;
2066 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002067
Matthew Ranostay87d48362007-07-17 11:52:24 +02002068 if (!spec->pin_configs)
2069 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002070
Matthew Ranostay87d48362007-07-17 11:52:24 +02002071 for (i = 0; i < spec->num_pins; i++)
2072 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2073 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002074}
Matt2f2f4252005-04-13 14:45:30 +02002075
Matt2f2f4252005-04-13 14:45:30 +02002076/*
2077 * Analog playback callbacks
2078 */
2079static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2080 struct hda_codec *codec,
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;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002084 if (spec->stream_delay)
2085 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002086 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2087 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002088}
2089
2090static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2091 struct hda_codec *codec,
2092 unsigned int stream_tag,
2093 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002094 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002095{
2096 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002097 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002098}
2099
2100static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2101 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002102 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002103{
2104 struct sigmatel_spec *spec = codec->spec;
2105 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2106}
2107
2108/*
Mattdabbed62005-06-14 10:19:34 +02002109 * Digital playback callbacks
2110 */
2111static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2112 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002113 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002114{
2115 struct sigmatel_spec *spec = codec->spec;
2116 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2117}
2118
2119static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2120 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002121 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002122{
2123 struct sigmatel_spec *spec = codec->spec;
2124 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2125}
2126
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002127static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2128 struct hda_codec *codec,
2129 unsigned int stream_tag,
2130 unsigned int format,
2131 struct snd_pcm_substream *substream)
2132{
2133 struct sigmatel_spec *spec = codec->spec;
2134 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2135 stream_tag, format, substream);
2136}
2137
Mattdabbed62005-06-14 10:19:34 +02002138
2139/*
Matt2f2f4252005-04-13 14:45:30 +02002140 * Analog capture callbacks
2141 */
2142static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2143 struct hda_codec *codec,
2144 unsigned int stream_tag,
2145 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002146 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002147{
2148 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002149 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002150
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002151 if (spec->powerdown_adcs) {
2152 msleep(40);
2153 snd_hda_codec_write_cache(codec, nid, 0,
2154 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2155 }
2156 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002157 return 0;
2158}
2159
2160static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2161 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002162 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002163{
2164 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002165 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002166
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002167 snd_hda_codec_cleanup_stream(codec, nid);
2168 if (spec->powerdown_adcs)
2169 snd_hda_codec_write_cache(codec, nid, 0,
2170 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002171 return 0;
2172}
2173
Mattdabbed62005-06-14 10:19:34 +02002174static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2175 .substreams = 1,
2176 .channels_min = 2,
2177 .channels_max = 2,
2178 /* NID is set in stac92xx_build_pcms */
2179 .ops = {
2180 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002181 .close = stac92xx_dig_playback_pcm_close,
2182 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002183 },
2184};
2185
2186static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2187 .substreams = 1,
2188 .channels_min = 2,
2189 .channels_max = 2,
2190 /* NID is set in stac92xx_build_pcms */
2191};
2192
Matt2f2f4252005-04-13 14:45:30 +02002193static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2194 .substreams = 1,
2195 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002196 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002197 .nid = 0x02, /* NID to query formats and rates */
2198 .ops = {
2199 .open = stac92xx_playback_pcm_open,
2200 .prepare = stac92xx_playback_pcm_prepare,
2201 .cleanup = stac92xx_playback_pcm_cleanup
2202 },
2203};
2204
Matt Porter3cc08dc2006-01-23 15:27:49 +01002205static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2206 .substreams = 1,
2207 .channels_min = 2,
2208 .channels_max = 2,
2209 .nid = 0x06, /* NID to query formats and rates */
2210 .ops = {
2211 .open = stac92xx_playback_pcm_open,
2212 .prepare = stac92xx_playback_pcm_prepare,
2213 .cleanup = stac92xx_playback_pcm_cleanup
2214 },
2215};
2216
Matt2f2f4252005-04-13 14:45:30 +02002217static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002218 .channels_min = 2,
2219 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002220 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002221 .ops = {
2222 .prepare = stac92xx_capture_pcm_prepare,
2223 .cleanup = stac92xx_capture_pcm_cleanup
2224 },
2225};
2226
2227static int stac92xx_build_pcms(struct hda_codec *codec)
2228{
2229 struct sigmatel_spec *spec = codec->spec;
2230 struct hda_pcm *info = spec->pcm_rec;
2231
2232 codec->num_pcms = 1;
2233 codec->pcm_info = info;
2234
Mattc7d4b2f2005-06-27 14:59:41 +02002235 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002236 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002237 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002238 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002239 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002240
2241 if (spec->alt_switch) {
2242 codec->num_pcms++;
2243 info++;
2244 info->name = "STAC92xx Analog Alt";
2245 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2246 }
Matt2f2f4252005-04-13 14:45:30 +02002247
Mattdabbed62005-06-14 10:19:34 +02002248 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2249 codec->num_pcms++;
2250 info++;
2251 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002252 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002253 if (spec->multiout.dig_out_nid) {
2254 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2255 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2256 }
2257 if (spec->dig_in_nid) {
2258 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2259 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2260 }
2261 }
2262
Matt2f2f4252005-04-13 14:45:30 +02002263 return 0;
2264}
2265
Takashi Iwaic960a032006-03-23 17:06:28 +01002266static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2267{
2268 unsigned int pincap = snd_hda_param_read(codec, nid,
2269 AC_PAR_PIN_CAP);
2270 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2271 if (pincap & AC_PINCAP_VREF_100)
2272 return AC_PINCTL_VREF_100;
2273 if (pincap & AC_PINCAP_VREF_80)
2274 return AC_PINCTL_VREF_80;
2275 if (pincap & AC_PINCAP_VREF_50)
2276 return AC_PINCTL_VREF_50;
2277 if (pincap & AC_PINCAP_VREF_GRD)
2278 return AC_PINCTL_VREF_GRD;
2279 return 0;
2280}
2281
Matt Porter403d1942005-11-29 15:00:51 +01002282static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2283
2284{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002285 snd_hda_codec_write_cache(codec, nid, 0,
2286 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002287}
2288
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002289#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2290
2291static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2292 struct snd_ctl_elem_value *ucontrol)
2293{
2294 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2295 struct sigmatel_spec *spec = codec->spec;
2296
2297 ucontrol->value.integer.value[0] = spec->hp_switch;
2298 return 0;
2299}
2300
2301static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2302 struct snd_ctl_elem_value *ucontrol)
2303{
2304 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2305 struct sigmatel_spec *spec = codec->spec;
2306
2307 spec->hp_switch = ucontrol->value.integer.value[0];
2308
2309 /* check to be sure that the ports are upto date with
2310 * switch changes
2311 */
2312 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2313
2314 return 1;
2315}
2316
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002317#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002318
2319static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2320{
2321 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2322 struct sigmatel_spec *spec = codec->spec;
2323 int io_idx = kcontrol-> private_value & 0xff;
2324
2325 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2326 return 0;
2327}
2328
2329static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2330{
2331 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2332 struct sigmatel_spec *spec = codec->spec;
2333 hda_nid_t nid = kcontrol->private_value >> 8;
2334 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002335 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002336
2337 spec->io_switch[io_idx] = val;
2338
2339 if (val)
2340 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002341 else {
2342 unsigned int pinctl = AC_PINCTL_IN_EN;
2343 if (io_idx) /* set VREF for mic */
2344 pinctl |= stac92xx_get_vref(codec, nid);
2345 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2346 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002347
2348 /* check the auto-mute again: we need to mute/unmute the speaker
2349 * appropriately according to the pin direction
2350 */
2351 if (spec->hp_detect)
2352 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2353
Matt Porter403d1942005-11-29 15:00:51 +01002354 return 1;
2355}
2356
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002357#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2358
2359static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2360 struct snd_ctl_elem_value *ucontrol)
2361{
2362 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2363 struct sigmatel_spec *spec = codec->spec;
2364
2365 ucontrol->value.integer.value[0] = spec->clfe_swap;
2366 return 0;
2367}
2368
2369static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2370 struct snd_ctl_elem_value *ucontrol)
2371{
2372 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2373 struct sigmatel_spec *spec = codec->spec;
2374 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002375 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002376
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002377 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002378 return 0;
2379
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002380 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002381
2382 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2383 spec->clfe_swap ? 0x4 : 0x0);
2384
2385 return 1;
2386}
2387
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002388#define STAC_CODEC_HP_SWITCH(xname) \
2389 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2390 .name = xname, \
2391 .index = 0, \
2392 .info = stac92xx_hp_switch_info, \
2393 .get = stac92xx_hp_switch_get, \
2394 .put = stac92xx_hp_switch_put, \
2395 }
2396
Matt Porter403d1942005-11-29 15:00:51 +01002397#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2398 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2399 .name = xname, \
2400 .index = 0, \
2401 .info = stac92xx_io_switch_info, \
2402 .get = stac92xx_io_switch_get, \
2403 .put = stac92xx_io_switch_put, \
2404 .private_value = xpval, \
2405 }
2406
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002407#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2408 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2409 .name = xname, \
2410 .index = 0, \
2411 .info = stac92xx_clfe_switch_info, \
2412 .get = stac92xx_clfe_switch_get, \
2413 .put = stac92xx_clfe_switch_put, \
2414 .private_value = xpval, \
2415 }
Matt Porter403d1942005-11-29 15:00:51 +01002416
Mattc7d4b2f2005-06-27 14:59:41 +02002417enum {
2418 STAC_CTL_WIDGET_VOL,
2419 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002420 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002421 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002422 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002423 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002424};
2425
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002426static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002427 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2428 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002429 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002430 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002431 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002432 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002433};
2434
2435/* add dynamic controls */
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002436static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
2437 int idx, const char *name, unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002438{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002439 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002440
2441 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2442 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2443
2444 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2445 if (! knew)
2446 return -ENOMEM;
2447 if (spec->kctl_alloc) {
2448 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2449 kfree(spec->kctl_alloc);
2450 }
2451 spec->kctl_alloc = knew;
2452 spec->num_kctl_alloc = num;
2453 }
2454
2455 knew = &spec->kctl_alloc[spec->num_kctl_used];
2456 *knew = stac92xx_control_templates[type];
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002457 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002458 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002459 if (! knew->name)
2460 return -ENOMEM;
2461 knew->private_value = val;
2462 spec->num_kctl_used++;
2463 return 0;
2464}
2465
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002466
2467/* add dynamic controls */
2468static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2469 const char *name, unsigned long val)
2470{
2471 return stac92xx_add_control_idx(spec, type, 0, name, val);
2472}
2473
Matt Porter403d1942005-11-29 15:00:51 +01002474/* flag inputs as additional dynamic lineouts */
2475static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2476{
2477 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002478 unsigned int wcaps, wtype;
2479 int i, num_dacs = 0;
2480
2481 /* use the wcaps cache to count all DACs available for line-outs */
2482 for (i = 0; i < codec->num_nodes; i++) {
2483 wcaps = codec->wcaps[i];
2484 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002485
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002486 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2487 num_dacs++;
2488 }
Matt Porter403d1942005-11-29 15:00:51 +01002489
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002490 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2491
Matt Porter403d1942005-11-29 15:00:51 +01002492 switch (cfg->line_outs) {
2493 case 3:
2494 /* add line-in as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002495 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002496 cfg->line_out_pins[cfg->line_outs] =
2497 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002498 spec->line_switch = 1;
2499 cfg->line_outs++;
2500 }
2501 break;
2502 case 2:
2503 /* add line-in as clfe and mic as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002504 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002505 cfg->line_out_pins[cfg->line_outs] =
2506 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002507 spec->line_switch = 1;
2508 cfg->line_outs++;
2509 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002510 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002511 cfg->line_out_pins[cfg->line_outs] =
2512 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002513 spec->mic_switch = 1;
2514 cfg->line_outs++;
2515 }
2516 break;
2517 case 1:
2518 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002519 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002520 cfg->line_out_pins[cfg->line_outs] =
2521 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002522 spec->line_switch = 1;
2523 cfg->line_outs++;
2524 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002525 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002526 cfg->line_out_pins[cfg->line_outs] =
2527 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002528 spec->mic_switch = 1;
2529 cfg->line_outs++;
2530 }
2531 break;
2532 }
2533
2534 return 0;
2535}
2536
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002537
2538static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2539{
2540 int i;
2541
2542 for (i = 0; i < spec->multiout.num_dacs; i++) {
2543 if (spec->multiout.dac_nids[i] == nid)
2544 return 1;
2545 }
2546
2547 return 0;
2548}
2549
Matt Porter3cc08dc2006-01-23 15:27:49 +01002550/*
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002551 * Fill in the dac_nids table from the parsed pin configuration
2552 * This function only works when every pin in line_out_pins[]
2553 * contains atleast one DAC in its connection list. Some 92xx
2554 * codecs are not connected directly to a DAC, such as the 9200
2555 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002556 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002557static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002558 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002559{
2560 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002561 int i, j, conn_len = 0;
2562 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2563 unsigned int wcaps, wtype;
2564
Mattc7d4b2f2005-06-27 14:59:41 +02002565 for (i = 0; i < cfg->line_outs; i++) {
2566 nid = cfg->line_out_pins[i];
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002567 conn_len = snd_hda_get_connections(codec, nid, conn,
2568 HDA_MAX_CONNECTIONS);
2569 for (j = 0; j < conn_len; j++) {
2570 wcaps = snd_hda_param_read(codec, conn[j],
2571 AC_PAR_AUDIO_WIDGET_CAP);
2572 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002573 if (wtype != AC_WID_AUD_OUT ||
2574 (wcaps & AC_WCAP_DIGITAL))
2575 continue;
2576 /* conn[j] is a DAC routed to this line-out */
2577 if (!is_in_dac_nids(spec, conn[j]))
2578 break;
2579 }
2580
2581 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002582 if (spec->multiout.num_dacs > 0) {
2583 /* we have already working output pins,
2584 * so let's drop the broken ones again
2585 */
2586 cfg->line_outs = spec->multiout.num_dacs;
2587 break;
2588 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002589 /* error out, no available DAC found */
2590 snd_printk(KERN_ERR
2591 "%s: No available DAC for pin 0x%x\n",
2592 __func__, nid);
2593 return -ENODEV;
2594 }
2595
2596 spec->multiout.dac_nids[i] = conn[j];
2597 spec->multiout.num_dacs++;
2598 if (conn_len > 1) {
2599 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002600 snd_hda_codec_write_cache(codec, nid, 0,
2601 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002602
2603 }
Mattc7d4b2f2005-06-27 14:59:41 +02002604 }
2605
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002606 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2607 spec->multiout.num_dacs,
2608 spec->multiout.dac_nids[0],
2609 spec->multiout.dac_nids[1],
2610 spec->multiout.dac_nids[2],
2611 spec->multiout.dac_nids[3],
2612 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002613 return 0;
2614}
2615
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002616/* create volume control/switch for the given prefx type */
2617static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2618{
2619 char name[32];
2620 int err;
2621
2622 sprintf(name, "%s Playback Volume", pfx);
2623 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2624 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2625 if (err < 0)
2626 return err;
2627 sprintf(name, "%s Playback Switch", pfx);
2628 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2629 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2630 if (err < 0)
2631 return err;
2632 return 0;
2633}
2634
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002635static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2636{
2637 if (!spec->multiout.hp_nid)
2638 spec->multiout.hp_nid = nid;
2639 else if (spec->multiout.num_dacs > 4) {
2640 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2641 return 1;
2642 } else {
2643 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2644 spec->multiout.num_dacs++;
2645 }
2646 return 0;
2647}
2648
2649static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2650{
2651 if (is_in_dac_nids(spec, nid))
2652 return 1;
2653 if (spec->multiout.hp_nid == nid)
2654 return 1;
2655 return 0;
2656}
2657
Mattc7d4b2f2005-06-27 14:59:41 +02002658/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002659static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002660 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002661{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002662 static const char *chname[4] = {
2663 "Front", "Surround", NULL /*CLFE*/, "Side"
2664 };
Mattc7d4b2f2005-06-27 14:59:41 +02002665 hda_nid_t nid;
2666 int i, err;
2667
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002668 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002669 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002670
2671
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002672 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002673 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002674 continue;
2675
2676 nid = spec->multiout.dac_nids[i];
2677
2678 if (i == 2) {
2679 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002680 err = create_controls(spec, "Center", nid, 1);
2681 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002682 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002683 err = create_controls(spec, "LFE", nid, 2);
2684 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002685 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002686
2687 wid_caps = get_wcaps(codec, nid);
2688
2689 if (wid_caps & AC_WCAP_LR_SWAP) {
2690 err = stac92xx_add_control(spec,
2691 STAC_CTL_WIDGET_CLFE_SWITCH,
2692 "Swap Center/LFE Playback Switch", nid);
2693
2694 if (err < 0)
2695 return err;
2696 }
2697
Mattc7d4b2f2005-06-27 14:59:41 +02002698 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002699 err = create_controls(spec, chname[i], nid, 3);
2700 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002701 return err;
2702 }
2703 }
2704
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002705 if (cfg->hp_outs > 1) {
2706 err = stac92xx_add_control(spec,
2707 STAC_CTL_WIDGET_HP_SWITCH,
2708 "Headphone as Line Out Switch", 0);
2709 if (err < 0)
2710 return err;
2711 }
2712
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002713 if (spec->line_switch) {
2714 nid = cfg->input_pins[AUTO_PIN_LINE];
2715 pincap = snd_hda_param_read(codec, nid,
2716 AC_PAR_PIN_CAP);
2717 if (pincap & AC_PINCAP_OUT) {
2718 err = stac92xx_add_control(spec,
2719 STAC_CTL_WIDGET_IO_SWITCH,
2720 "Line In as Output Switch", nid << 8);
2721 if (err < 0)
2722 return err;
2723 }
2724 }
Matt Porter403d1942005-11-29 15:00:51 +01002725
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002726 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002727 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002728 unsigned int mic_pin = AUTO_PIN_MIC;
2729again:
2730 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002731 def_conf = snd_hda_codec_read(codec, nid, 0,
2732 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002733 /* some laptops have an internal analog microphone
2734 * which can't be used as a output */
2735 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2736 pincap = snd_hda_param_read(codec, nid,
2737 AC_PAR_PIN_CAP);
2738 if (pincap & AC_PINCAP_OUT) {
2739 err = stac92xx_add_control(spec,
2740 STAC_CTL_WIDGET_IO_SWITCH,
2741 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002742 nid = snd_hda_codec_read(codec, nid, 0,
2743 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2744 if (!check_in_dac_nids(spec, nid))
2745 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002746 if (err < 0)
2747 return err;
2748 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002749 } else if (mic_pin == AUTO_PIN_MIC) {
2750 mic_pin = AUTO_PIN_FRONT_MIC;
2751 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002752 }
2753 }
Matt Porter403d1942005-11-29 15:00:51 +01002754
Mattc7d4b2f2005-06-27 14:59:41 +02002755 return 0;
2756}
2757
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002758/* add playback controls for Speaker and HP outputs */
2759static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2760 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002761{
2762 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002763 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002764 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002765
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002766 old_num_dacs = spec->multiout.num_dacs;
2767 for (i = 0; i < cfg->hp_outs; i++) {
2768 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2769 if (wid_caps & AC_WCAP_UNSOL_CAP)
2770 spec->hp_detect = 1;
2771 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2772 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2773 if (check_in_dac_nids(spec, nid))
2774 nid = 0;
2775 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002776 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002777 add_spec_dacs(spec, nid);
2778 }
2779 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002780 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002781 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2782 if (check_in_dac_nids(spec, nid))
2783 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002784 if (! nid)
2785 continue;
2786 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002787 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002788 for (i = 0; i < cfg->line_outs; i++) {
2789 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2790 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2791 if (check_in_dac_nids(spec, nid))
2792 nid = 0;
2793 if (! nid)
2794 continue;
2795 add_spec_dacs(spec, nid);
2796 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002797 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2798 static const char *pfxs[] = {
2799 "Speaker", "External Speaker", "Speaker2",
2800 };
2801 err = create_controls(spec, pfxs[i - old_num_dacs],
2802 spec->multiout.dac_nids[i], 3);
2803 if (err < 0)
2804 return err;
2805 }
2806 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002807 err = create_controls(spec, "Headphone",
2808 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002809 if (err < 0)
2810 return err;
2811 }
Mattc7d4b2f2005-06-27 14:59:41 +02002812
2813 return 0;
2814}
2815
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002816/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002817static const char *stac92xx_mono_labels[4] = {
2818 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002819};
2820
2821/* create mono mux for mono out on capable codecs */
2822static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2823{
2824 struct sigmatel_spec *spec = codec->spec;
2825 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2826 int i, num_cons;
2827 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2828
2829 num_cons = snd_hda_get_connections(codec,
2830 spec->mono_nid,
2831 con_lst,
2832 HDA_MAX_NUM_INPUTS);
2833 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2834 return -EINVAL;
2835
2836 for (i = 0; i < num_cons; i++) {
2837 mono_mux->items[mono_mux->num_items].label =
2838 stac92xx_mono_labels[i];
2839 mono_mux->items[mono_mux->num_items].index = i;
2840 mono_mux->num_items++;
2841 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002842
2843 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2844 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002845}
2846
Matthew Ranostay1cd22242008-07-18 18:20:52 +02002847/* create PC beep volume controls */
2848static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
2849 hda_nid_t nid)
2850{
2851 struct sigmatel_spec *spec = codec->spec;
2852 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
2853 int err;
2854
2855 /* check for mute support for the the amp */
2856 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
2857 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2858 "PC Beep Playback Switch",
2859 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2860 if (err < 0)
2861 return err;
2862 }
2863
2864 /* check to see if there is volume support for the amp */
2865 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2866 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2867 "PC Beep Playback Volume",
2868 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2869 if (err < 0)
2870 return err;
2871 }
2872 return 0;
2873}
2874
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002875static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
2876{
2877 struct sigmatel_spec *spec = codec->spec;
2878 int wcaps, nid, i, err = 0;
2879
2880 for (i = 0; i < spec->num_muxes; i++) {
2881 nid = spec->mux_nids[i];
2882 wcaps = get_wcaps(codec, nid);
2883
2884 if (wcaps & AC_WCAP_OUT_AMP) {
2885 err = stac92xx_add_control_idx(spec,
2886 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
2887 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2888 if (err < 0)
2889 return err;
2890 }
2891 }
2892 return 0;
2893};
2894
Matthew Ranostayd9737752008-09-07 12:03:41 +02002895static const char *stac92xx_spdif_labels[3] = {
2896 "Digital Playback", "Analog Mux 1", "Analog Mux 2"
2897};
2898
2899static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
2900{
2901 struct sigmatel_spec *spec = codec->spec;
2902 struct hda_input_mux *spdif_mux = &spec->private_smux;
2903 int i, num_cons;
2904 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_spdif_labels)];
2905
2906 num_cons = snd_hda_get_connections(codec,
2907 spec->smux_nids[0],
2908 con_lst,
2909 HDA_MAX_NUM_INPUTS);
2910 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_spdif_labels))
2911 return -EINVAL;
2912
2913 for (i = 0; i < num_cons; i++) {
2914 spdif_mux->items[spdif_mux->num_items].label =
2915 stac92xx_spdif_labels[i];
2916 spdif_mux->items[spdif_mux->num_items].index = i;
2917 spdif_mux->num_items++;
2918 }
2919
2920 return 0;
2921}
2922
Matt Porter8b657272006-10-26 17:12:59 +02002923/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002924static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002925 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2926 "Digital Mic 3", "Digital Mic 4"
2927};
2928
2929/* create playback/capture controls for input pins on dmic capable codecs */
2930static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2931 const struct auto_pin_cfg *cfg)
2932{
2933 struct sigmatel_spec *spec = codec->spec;
2934 struct hda_input_mux *dimux = &spec->private_dimux;
2935 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002936 int err, i, j;
2937 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002938
2939 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2940 dimux->items[dimux->num_items].index = 0;
2941 dimux->num_items++;
2942
2943 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002944 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002945 int index;
2946 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002947 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002948 unsigned int def_conf;
2949
2950 def_conf = snd_hda_codec_read(codec,
2951 spec->dmic_nids[i],
2952 0,
2953 AC_VERB_GET_CONFIG_DEFAULT,
2954 0);
2955 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2956 continue;
2957
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002958 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002959 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002960 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002961 con_lst,
2962 HDA_MAX_NUM_INPUTS);
2963 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002964 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002965 index = j;
2966 goto found;
2967 }
2968 continue;
2969found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002970 wcaps = get_wcaps(codec, nid) &
2971 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002972
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002973 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002974 sprintf(name, "%s Capture Volume",
2975 stac92xx_dmic_labels[dimux->num_items]);
2976
2977 err = stac92xx_add_control(spec,
2978 STAC_CTL_WIDGET_VOL,
2979 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002980 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2981 (wcaps & AC_WCAP_OUT_AMP) ?
2982 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002983 if (err < 0)
2984 return err;
2985 }
2986
Matt Porter8b657272006-10-26 17:12:59 +02002987 dimux->items[dimux->num_items].label =
2988 stac92xx_dmic_labels[dimux->num_items];
2989 dimux->items[dimux->num_items].index = index;
2990 dimux->num_items++;
2991 }
2992
2993 return 0;
2994}
2995
Mattc7d4b2f2005-06-27 14:59:41 +02002996/* create playback/capture controls for input pins */
2997static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2998{
2999 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003000 struct hda_input_mux *imux = &spec->private_imux;
3001 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3002 int i, j, k;
3003
3004 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003005 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003006
Takashi Iwai314634b2006-09-21 11:56:18 +02003007 if (!cfg->input_pins[i])
3008 continue;
3009 index = -1;
3010 for (j = 0; j < spec->num_muxes; j++) {
3011 int num_cons;
3012 num_cons = snd_hda_get_connections(codec,
3013 spec->mux_nids[j],
3014 con_lst,
3015 HDA_MAX_NUM_INPUTS);
3016 for (k = 0; k < num_cons; k++)
3017 if (con_lst[k] == cfg->input_pins[i]) {
3018 index = k;
3019 goto found;
3020 }
Mattc7d4b2f2005-06-27 14:59:41 +02003021 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003022 continue;
3023 found:
3024 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3025 imux->items[imux->num_items].index = index;
3026 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003027 }
3028
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003029 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003030 /*
3031 * Set the current input for the muxes.
3032 * The STAC9221 has two input muxes with identical source
3033 * NID lists. Hopefully this won't get confused.
3034 */
3035 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003036 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3037 AC_VERB_SET_CONNECT_SEL,
3038 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003039 }
3040 }
3041
Mattc7d4b2f2005-06-27 14:59:41 +02003042 return 0;
3043}
3044
Mattc7d4b2f2005-06-27 14:59:41 +02003045static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3046{
3047 struct sigmatel_spec *spec = codec->spec;
3048 int i;
3049
3050 for (i = 0; i < spec->autocfg.line_outs; i++) {
3051 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3052 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3053 }
3054}
3055
3056static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3057{
3058 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003059 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003060
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003061 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3062 hda_nid_t pin;
3063 pin = spec->autocfg.hp_pins[i];
3064 if (pin) /* connect to front */
3065 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3066 }
3067 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3068 hda_nid_t pin;
3069 pin = spec->autocfg.speaker_pins[i];
3070 if (pin) /* connect to front */
3071 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3072 }
Mattc7d4b2f2005-06-27 14:59:41 +02003073}
3074
Matt Porter3cc08dc2006-01-23 15:27:49 +01003075static 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 +02003076{
3077 struct sigmatel_spec *spec = codec->spec;
3078 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003079 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003080
Matt Porter8b657272006-10-26 17:12:59 +02003081 if ((err = snd_hda_parse_pin_def_config(codec,
3082 &spec->autocfg,
3083 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003084 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003085 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003086 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003087
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003088 /* If we have no real line-out pin and multiple hp-outs, HPs should
3089 * be set up as multi-channel outputs.
3090 */
3091 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3092 spec->autocfg.hp_outs > 1) {
3093 /* Copy hp_outs to line_outs, backup line_outs in
3094 * speaker_outs so that the following routines can handle
3095 * HP pins as primary outputs.
3096 */
3097 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3098 sizeof(spec->autocfg.line_out_pins));
3099 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3100 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3101 sizeof(spec->autocfg.hp_pins));
3102 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3103 hp_speaker_swap = 1;
3104 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003105 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003106 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3107 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003108 u32 caps = query_amp_caps(codec,
3109 spec->autocfg.mono_out_pin, dir);
3110 hda_nid_t conn_list[1];
3111
3112 /* get the mixer node and then the mono mux if it exists */
3113 if (snd_hda_get_connections(codec,
3114 spec->autocfg.mono_out_pin, conn_list, 1) &&
3115 snd_hda_get_connections(codec, conn_list[0],
3116 conn_list, 1)) {
3117
3118 int wcaps = get_wcaps(codec, conn_list[0]);
3119 int wid_type = (wcaps & AC_WCAP_TYPE)
3120 >> AC_WCAP_TYPE_SHIFT;
3121 /* LR swap check, some stac925x have a mux that
3122 * changes the DACs output path instead of the
3123 * mono-mux path.
3124 */
3125 if (wid_type == AC_WID_AUD_SEL &&
3126 !(wcaps & AC_WCAP_LR_SWAP))
3127 spec->mono_nid = conn_list[0];
3128 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003129 if (dir) {
3130 hda_nid_t nid = spec->autocfg.mono_out_pin;
3131
3132 /* most mono outs have a least a mute/unmute switch */
3133 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3134 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3135 "Mono Playback Switch",
3136 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003137 if (err < 0)
3138 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003139 /* check for volume support for the amp */
3140 if ((caps & AC_AMPCAP_NUM_STEPS)
3141 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3142 err = stac92xx_add_control(spec,
3143 STAC_CTL_WIDGET_VOL,
3144 "Mono Playback Volume",
3145 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3146 if (err < 0)
3147 return err;
3148 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003149 }
3150
3151 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3152 AC_PINCTL_OUT_EN);
3153 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003154
Matt Porter403d1942005-11-29 15:00:51 +01003155 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3156 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003157 if (spec->multiout.num_dacs == 0)
3158 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3159 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003160
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003161 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3162
3163 if (err < 0)
3164 return err;
3165
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003166 /* setup analog beep controls */
3167 if (spec->anabeep_nid > 0) {
3168 err = stac92xx_auto_create_beep_ctls(codec,
3169 spec->anabeep_nid);
3170 if (err < 0)
3171 return err;
3172 }
3173
3174 /* setup digital beep controls and input device */
3175#ifdef CONFIG_SND_HDA_INPUT_BEEP
3176 if (spec->digbeep_nid > 0) {
3177 hda_nid_t nid = spec->digbeep_nid;
3178
3179 err = stac92xx_auto_create_beep_ctls(codec, nid);
3180 if (err < 0)
3181 return err;
3182 err = snd_hda_attach_beep_device(codec, nid);
3183 if (err < 0)
3184 return err;
3185 }
3186#endif
3187
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003188 if (hp_speaker_swap == 1) {
3189 /* Restore the hp_outs and line_outs */
3190 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3191 sizeof(spec->autocfg.line_out_pins));
3192 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3193 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3194 sizeof(spec->autocfg.speaker_pins));
3195 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3196 memset(spec->autocfg.speaker_pins, 0,
3197 sizeof(spec->autocfg.speaker_pins));
3198 spec->autocfg.speaker_outs = 0;
3199 }
3200
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003201 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3202
3203 if (err < 0)
3204 return err;
3205
3206 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3207
3208 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003209 return err;
3210
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003211 if (spec->mono_nid > 0) {
3212 err = stac92xx_auto_create_mono_output_ctls(codec);
3213 if (err < 0)
3214 return err;
3215 }
3216
Matt Porter8b657272006-10-26 17:12:59 +02003217 if (spec->num_dmics > 0)
3218 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3219 &spec->autocfg)) < 0)
3220 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003221 if (spec->num_muxes > 0) {
3222 err = stac92xx_auto_create_mux_input_ctls(codec);
3223 if (err < 0)
3224 return err;
3225 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003226 if (spec->num_smuxes > 0) {
3227 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3228 if (err < 0)
3229 return err;
3230 }
Matt Porter8b657272006-10-26 17:12:59 +02003231
Mattc7d4b2f2005-06-27 14:59:41 +02003232 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003233 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003234 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003235
Takashi Iwai82bc9552006-03-21 11:24:42 +01003236 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003237 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003238 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003239 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003240
3241 if (spec->kctl_alloc)
3242 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3243
3244 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003245 if (!spec->dinput_mux)
3246 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003247 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003248 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003249
3250 return 1;
3251}
3252
Takashi Iwai82bc9552006-03-21 11:24:42 +01003253/* add playback controls for HP output */
3254static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3255 struct auto_pin_cfg *cfg)
3256{
3257 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003258 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003259 unsigned int wid_caps;
3260
3261 if (! pin)
3262 return 0;
3263
3264 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003265 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003266 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003267
3268 return 0;
3269}
3270
Richard Fish160ea0d2006-09-06 13:58:25 +02003271/* add playback controls for LFE output */
3272static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3273 struct auto_pin_cfg *cfg)
3274{
3275 struct sigmatel_spec *spec = codec->spec;
3276 int err;
3277 hda_nid_t lfe_pin = 0x0;
3278 int i;
3279
3280 /*
3281 * search speaker outs and line outs for a mono speaker pin
3282 * with an amp. If one is found, add LFE controls
3283 * for it.
3284 */
3285 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3286 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003287 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003288 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3289 if (wcaps == AC_WCAP_OUT_AMP)
3290 /* found a mono speaker with an amp, must be lfe */
3291 lfe_pin = pin;
3292 }
3293
3294 /* if speaker_outs is 0, then speakers may be in line_outs */
3295 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3296 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3297 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003298 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003299 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003300 AC_VERB_GET_CONFIG_DEFAULT,
3301 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003302 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003303 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003304 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3305 if (wcaps == AC_WCAP_OUT_AMP)
3306 /* found a mono speaker with an amp,
3307 must be lfe */
3308 lfe_pin = pin;
3309 }
3310 }
3311 }
3312
3313 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003314 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003315 if (err < 0)
3316 return err;
3317 }
3318
3319 return 0;
3320}
3321
Mattc7d4b2f2005-06-27 14:59:41 +02003322static int stac9200_parse_auto_config(struct hda_codec *codec)
3323{
3324 struct sigmatel_spec *spec = codec->spec;
3325 int err;
3326
Kailang Yangdf694da2005-12-05 19:42:22 +01003327 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003328 return err;
3329
3330 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3331 return err;
3332
Takashi Iwai82bc9552006-03-21 11:24:42 +01003333 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3334 return err;
3335
Richard Fish160ea0d2006-09-06 13:58:25 +02003336 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3337 return err;
3338
Takashi Iwai82bc9552006-03-21 11:24:42 +01003339 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003340 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003341 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003342 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003343
3344 if (spec->kctl_alloc)
3345 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3346
3347 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003348 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003349
3350 return 1;
3351}
3352
Sam Revitch62fe78e2006-05-10 15:09:17 +02003353/*
3354 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3355 * funky external mute control using GPIO pins.
3356 */
3357
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003358static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003359 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003360{
3361 unsigned int gpiostate, gpiomask, gpiodir;
3362
3363 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3364 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003365 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003366
3367 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3368 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003369 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003370
3371 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3372 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003373 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003374
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003375 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003376 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3377
3378 snd_hda_codec_write(codec, codec->afg, 0,
3379 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003380 snd_hda_codec_read(codec, codec->afg, 0,
3381 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003382
3383 msleep(1);
3384
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003385 snd_hda_codec_read(codec, codec->afg, 0,
3386 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003387}
3388
Takashi Iwai314634b2006-09-21 11:56:18 +02003389static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3390 unsigned int event)
3391{
3392 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003393 snd_hda_codec_write_cache(codec, nid, 0,
3394 AC_VERB_SET_UNSOLICITED_ENABLE,
3395 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003396}
3397
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003398static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3399{
3400 int i;
3401 for (i = 0; i < cfg->hp_outs; i++)
3402 if (cfg->hp_pins[i] == nid)
3403 return 1; /* nid is a HP-Out */
3404
3405 return 0; /* nid is not a HP-Out */
3406};
3407
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003408static void stac92xx_power_down(struct hda_codec *codec)
3409{
3410 struct sigmatel_spec *spec = codec->spec;
3411
3412 /* power down inactive DACs */
3413 hda_nid_t *dac;
3414 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003415 if (!is_in_dac_nids(spec, *dac) &&
3416 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003417 snd_hda_codec_write_cache(codec, *dac, 0,
3418 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3419}
3420
Mattc7d4b2f2005-06-27 14:59:41 +02003421static int stac92xx_init(struct hda_codec *codec)
3422{
3423 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003424 struct auto_pin_cfg *cfg = &spec->autocfg;
3425 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003426
Mattc7d4b2f2005-06-27 14:59:41 +02003427 snd_hda_sequence_write(codec, spec->init);
3428
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003429 /* power down adcs initially */
3430 if (spec->powerdown_adcs)
3431 for (i = 0; i < spec->num_adcs; i++)
3432 snd_hda_codec_write_cache(codec,
3433 spec->adc_nids[i], 0,
3434 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003435 /* set up pins */
3436 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003437 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003438 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003439 enable_pin_detect(codec, cfg->hp_pins[i],
3440 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003441 /* force to enable the first line-out; the others are set up
3442 * in unsol_event
3443 */
3444 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3445 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003446 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003447 /* fake event to set up pins */
3448 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3449 } else {
3450 stac92xx_auto_init_multi_out(codec);
3451 stac92xx_auto_init_hp_out(codec);
3452 }
3453 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003454 hda_nid_t nid = cfg->input_pins[i];
3455 if (nid) {
3456 unsigned int pinctl = AC_PINCTL_IN_EN;
3457 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3458 pinctl |= stac92xx_get_vref(codec, nid);
3459 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3460 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003461 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003462 for (i = 0; i < spec->num_dmics; i++)
3463 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3464 AC_PINCTL_IN_EN);
3465 for (i = 0; i < spec->num_pwrs; i++) {
3466 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3467 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3468 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3469 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003470 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3471 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003472 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003473 /* outputs are only ports capable of power management
3474 * any attempts on powering down a input port cause the
3475 * referenced VREF to act quirky.
3476 */
3477 if (pinctl & AC_PINCTL_IN_EN)
3478 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003479 /* skip any ports that don't have jacks since presence
3480 * detection is useless */
3481 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003482 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003483 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3484 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3485 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003486 if (spec->dac_list)
3487 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003488 if (cfg->dig_out_pin)
3489 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3490 AC_PINCTL_OUT_EN);
3491 if (cfg->dig_in_pin)
3492 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3493 AC_PINCTL_IN_EN);
3494
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003495 stac_gpio_set(codec, spec->gpio_mask,
3496 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003497
Mattc7d4b2f2005-06-27 14:59:41 +02003498 return 0;
3499}
3500
Matt2f2f4252005-04-13 14:45:30 +02003501static void stac92xx_free(struct hda_codec *codec)
3502{
Mattc7d4b2f2005-06-27 14:59:41 +02003503 struct sigmatel_spec *spec = codec->spec;
3504 int i;
3505
3506 if (! spec)
3507 return;
3508
3509 if (spec->kctl_alloc) {
3510 for (i = 0; i < spec->num_kctl_used; i++)
3511 kfree(spec->kctl_alloc[i].name);
3512 kfree(spec->kctl_alloc);
3513 }
3514
Richard Fish11b44bb2006-08-23 18:31:34 +02003515 if (spec->bios_pin_configs)
3516 kfree(spec->bios_pin_configs);
3517
Mattc7d4b2f2005-06-27 14:59:41 +02003518 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003519 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003520}
3521
Matt4e550962005-07-04 17:51:39 +02003522static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3523 unsigned int flag)
3524{
3525 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3526 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003527
Takashi Iwaif9acba42007-05-29 18:01:06 +02003528 if (pin_ctl & AC_PINCTL_IN_EN) {
3529 /*
3530 * we need to check the current set-up direction of
3531 * shared input pins since they can be switched via
3532 * "xxx as Output" mixer switch
3533 */
3534 struct sigmatel_spec *spec = codec->spec;
3535 struct auto_pin_cfg *cfg = &spec->autocfg;
3536 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3537 spec->line_switch) ||
3538 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3539 spec->mic_switch))
3540 return;
3541 }
3542
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003543 /* if setting pin direction bits, clear the current
3544 direction bits first */
3545 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3546 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3547
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003548 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003549 AC_VERB_SET_PIN_WIDGET_CONTROL,
3550 pin_ctl | flag);
3551}
3552
3553static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3554 unsigned int flag)
3555{
3556 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3557 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003558 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003559 AC_VERB_SET_PIN_WIDGET_CONTROL,
3560 pin_ctl & ~flag);
3561}
3562
Jiang Zhe40c1d302007-11-12 13:05:16 +01003563static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003564{
3565 if (!nid)
3566 return 0;
3567 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003568 & (1 << 31)) {
3569 unsigned int pinctl;
3570 pinctl = snd_hda_codec_read(codec, nid, 0,
3571 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3572 if (pinctl & AC_PINCTL_IN_EN)
3573 return 0; /* mic- or line-input */
3574 else
3575 return 1; /* HP-output */
3576 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003577 return 0;
3578}
3579
3580static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003581{
3582 struct sigmatel_spec *spec = codec->spec;
3583 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003584 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003585 int i, presence;
3586
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003587 presence = 0;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003588 if (spec->gpio_mute)
3589 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3590 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3591
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003592 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003593 if (presence)
3594 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003595 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3596 break;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003597 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003598 }
Matt4e550962005-07-04 17:51:39 +02003599
3600 if (presence) {
3601 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003602 if (spec->hp_switch)
3603 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003604 for (i = 0; i < cfg->line_outs; i++)
3605 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3606 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003607 for (i = 0; i < cfg->speaker_outs; i++)
3608 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3609 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003610 if (spec->eapd_mask)
3611 stac_gpio_set(codec, spec->gpio_mask,
3612 spec->gpio_dir, spec->gpio_data &
3613 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003614 } else {
3615 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003616 if (spec->hp_switch)
3617 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003618 for (i = 0; i < cfg->line_outs; i++)
3619 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3620 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003621 for (i = 0; i < cfg->speaker_outs; i++)
3622 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3623 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003624 if (spec->eapd_mask)
3625 stac_gpio_set(codec, spec->gpio_mask,
3626 spec->gpio_dir, spec->gpio_data |
3627 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003628 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003629 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3630 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003631}
3632
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003633static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3634{
3635 struct sigmatel_spec *spec = codec->spec;
3636 hda_nid_t nid = spec->pwr_nids[idx];
3637 int presence, val;
3638 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3639 & 0x000000ff;
3640 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003641
3642 /* several codecs have two power down bits */
3643 if (spec->pwr_mapping)
3644 idx = spec->pwr_mapping[idx];
3645 else
3646 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003647
3648 if (presence)
3649 val &= ~idx;
3650 else
3651 val |= idx;
3652
3653 /* power down unused output ports */
3654 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3655};
3656
Takashi Iwai314634b2006-09-21 11:56:18 +02003657static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3658{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003659 struct sigmatel_spec *spec = codec->spec;
3660 int idx = res >> 26 & 0x0f;
3661
3662 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003663 case STAC_HP_EVENT:
3664 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003665 /* fallthru */
3666 case STAC_PWR_EVENT:
3667 if (spec->num_pwrs > 0)
3668 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003669 }
3670}
3671
Takashi Iwaicb53c622007-08-10 17:21:45 +02003672#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003673static int stac92xx_resume(struct hda_codec *codec)
3674{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003675 struct sigmatel_spec *spec = codec->spec;
3676
Richard Fish11b44bb2006-08-23 18:31:34 +02003677 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003678 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003679 stac_gpio_set(codec, spec->gpio_mask,
3680 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003681 snd_hda_codec_resume_amp(codec);
3682 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003683 /* power down inactive DACs */
3684 if (spec->dac_list)
3685 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003686 /* invoke unsolicited event to reset the HP state */
3687 if (spec->hp_detect)
3688 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003689 return 0;
3690}
3691#endif
3692
Matt2f2f4252005-04-13 14:45:30 +02003693static struct hda_codec_ops stac92xx_patch_ops = {
3694 .build_controls = stac92xx_build_controls,
3695 .build_pcms = stac92xx_build_pcms,
3696 .init = stac92xx_init,
3697 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003698 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003699#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003700 .resume = stac92xx_resume,
3701#endif
Matt2f2f4252005-04-13 14:45:30 +02003702};
3703
3704static int patch_stac9200(struct hda_codec *codec)
3705{
3706 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003707 int err;
Matt2f2f4252005-04-13 14:45:30 +02003708
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003709 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003710 if (spec == NULL)
3711 return -ENOMEM;
3712
3713 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003714 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003715 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003716 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3717 stac9200_models,
3718 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003719 if (spec->board_config < 0) {
3720 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3721 err = stac92xx_save_bios_config_regs(codec);
3722 if (err < 0) {
3723 stac92xx_free(codec);
3724 return err;
3725 }
3726 spec->pin_configs = spec->bios_pin_configs;
3727 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003728 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3729 stac92xx_set_config_regs(codec);
3730 }
Matt2f2f4252005-04-13 14:45:30 +02003731
3732 spec->multiout.max_channels = 2;
3733 spec->multiout.num_dacs = 1;
3734 spec->multiout.dac_nids = stac9200_dac_nids;
3735 spec->adc_nids = stac9200_adc_nids;
3736 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003737 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003738 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003739 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003740 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003741
Tobin Davisbf277782008-02-03 20:31:47 +01003742 if (spec->board_config == STAC_9200_GATEWAY ||
3743 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003744 spec->init = stac9200_eapd_init;
3745 else
3746 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003747 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003748
Takashi Iwai117f2572008-03-18 09:53:23 +01003749 if (spec->board_config == STAC_9200_PANASONIC) {
3750 spec->gpio_mask = spec->gpio_dir = 0x09;
3751 spec->gpio_data = 0x00;
3752 }
3753
Mattc7d4b2f2005-06-27 14:59:41 +02003754 err = stac9200_parse_auto_config(codec);
3755 if (err < 0) {
3756 stac92xx_free(codec);
3757 return err;
3758 }
Matt2f2f4252005-04-13 14:45:30 +02003759
3760 codec->patch_ops = stac92xx_patch_ops;
3761
3762 return 0;
3763}
3764
Tobin Davis8e21c342007-01-08 11:04:17 +01003765static int patch_stac925x(struct hda_codec *codec)
3766{
3767 struct sigmatel_spec *spec;
3768 int err;
3769
3770 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3771 if (spec == NULL)
3772 return -ENOMEM;
3773
3774 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003775 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003776 spec->pin_nids = stac925x_pin_nids;
3777 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3778 stac925x_models,
3779 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003780 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003781 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003782 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3783 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003784 err = stac92xx_save_bios_config_regs(codec);
3785 if (err < 0) {
3786 stac92xx_free(codec);
3787 return err;
3788 }
3789 spec->pin_configs = spec->bios_pin_configs;
3790 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3791 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3792 stac92xx_set_config_regs(codec);
3793 }
3794
3795 spec->multiout.max_channels = 2;
3796 spec->multiout.num_dacs = 1;
3797 spec->multiout.dac_nids = stac925x_dac_nids;
3798 spec->adc_nids = stac925x_adc_nids;
3799 spec->mux_nids = stac925x_mux_nids;
3800 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003801 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003802 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003803 switch (codec->vendor_id) {
3804 case 0x83847632: /* STAC9202 */
3805 case 0x83847633: /* STAC9202D */
3806 case 0x83847636: /* STAC9251 */
3807 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003808 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003809 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003810 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3811 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003812 break;
3813 default:
3814 spec->num_dmics = 0;
3815 break;
3816 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003817
3818 spec->init = stac925x_core_init;
3819 spec->mixer = stac925x_mixer;
3820
3821 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003822 if (!err) {
3823 if (spec->board_config < 0) {
3824 printk(KERN_WARNING "hda_codec: No auto-config is "
3825 "available, default to model=ref\n");
3826 spec->board_config = STAC_925x_REF;
3827 goto again;
3828 }
3829 err = -EINVAL;
3830 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003831 if (err < 0) {
3832 stac92xx_free(codec);
3833 return err;
3834 }
3835
3836 codec->patch_ops = stac92xx_patch_ops;
3837
3838 return 0;
3839}
3840
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003841static struct hda_input_mux stac92hd73xx_dmux = {
3842 .num_items = 4,
3843 .items = {
3844 { "Analog Inputs", 0x0b },
3845 { "CD", 0x08 },
3846 { "Digital Mic 1", 0x09 },
3847 { "Digital Mic 2", 0x0a },
3848 }
3849};
3850
3851static int patch_stac92hd73xx(struct hda_codec *codec)
3852{
3853 struct sigmatel_spec *spec;
3854 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3855 int err = 0;
3856
3857 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3858 if (spec == NULL)
3859 return -ENOMEM;
3860
3861 codec->spec = spec;
3862 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3863 spec->pin_nids = stac92hd73xx_pin_nids;
3864 spec->board_config = snd_hda_check_board_config(codec,
3865 STAC_92HD73XX_MODELS,
3866 stac92hd73xx_models,
3867 stac92hd73xx_cfg_tbl);
3868again:
3869 if (spec->board_config < 0) {
3870 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3871 " STAC92HD73XX, using BIOS defaults\n");
3872 err = stac92xx_save_bios_config_regs(codec);
3873 if (err < 0) {
3874 stac92xx_free(codec);
3875 return err;
3876 }
3877 spec->pin_configs = spec->bios_pin_configs;
3878 } else {
3879 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3880 stac92xx_set_config_regs(codec);
3881 }
3882
3883 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3884 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3885
3886 if (spec->multiout.num_dacs < 0) {
3887 printk(KERN_WARNING "hda_codec: Could not determine "
3888 "number of channels defaulting to DAC count\n");
3889 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3890 }
3891
3892 switch (spec->multiout.num_dacs) {
3893 case 0x3: /* 6 Channel */
3894 spec->mixer = stac92hd73xx_6ch_mixer;
3895 spec->init = stac92hd73xx_6ch_core_init;
3896 break;
3897 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003898 spec->mixer = stac92hd73xx_8ch_mixer;
3899 spec->init = stac92hd73xx_8ch_core_init;
3900 break;
3901 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003902 spec->mixer = stac92hd73xx_10ch_mixer;
3903 spec->init = stac92hd73xx_10ch_core_init;
3904 };
3905
3906 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3907 spec->aloopback_mask = 0x01;
3908 spec->aloopback_shift = 8;
3909
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003910 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003911 spec->mux_nids = stac92hd73xx_mux_nids;
3912 spec->adc_nids = stac92hd73xx_adc_nids;
3913 spec->dmic_nids = stac92hd73xx_dmic_nids;
3914 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003915 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003916
3917 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3918 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003919 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02003920 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003921 spec->dinput_mux = &stac92hd73xx_dmux;
3922 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003923 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003924 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003925
Matthew Ranostaya7662642008-02-21 07:51:14 +01003926 switch (spec->board_config) {
3927 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003928 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003929 switch (codec->subsystem_id) {
3930 case 0x1028025e: /* Analog Mics */
3931 case 0x1028025f:
3932 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3933 spec->num_dmics = 0;
3934 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003935 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003936 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003937 spec->init = dell_m6_core_init;
3938 /* fall-through */
3939 case 0x10280254:
3940 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003941 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3942 spec->num_dmics = 1;
3943 break;
3944 case 0x10280256: /* Both */
3945 case 0x10280057:
3946 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3947 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3948 spec->num_dmics = 1;
3949 break;
3950 }
3951 break;
3952 default:
3953 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3954 }
3955
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003956 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3957 spec->pwr_nids = stac92hd73xx_pwr_nids;
3958
Matthew Ranostayd9737752008-09-07 12:03:41 +02003959 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003960
3961 if (!err) {
3962 if (spec->board_config < 0) {
3963 printk(KERN_WARNING "hda_codec: No auto-config is "
3964 "available, default to model=ref\n");
3965 spec->board_config = STAC_92HD73XX_REF;
3966 goto again;
3967 }
3968 err = -EINVAL;
3969 }
3970
3971 if (err < 0) {
3972 stac92xx_free(codec);
3973 return err;
3974 }
3975
3976 codec->patch_ops = stac92xx_patch_ops;
3977
3978 return 0;
3979}
3980
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003981static struct hda_input_mux stac92hd83xxx_dmux = {
3982 .num_items = 3,
3983 .items = {
3984 { "Analog Inputs", 0x03 },
3985 { "Digital Mic 1", 0x04 },
3986 { "Digital Mic 2", 0x05 },
3987 }
3988};
3989
3990static int patch_stac92hd83xxx(struct hda_codec *codec)
3991{
3992 struct sigmatel_spec *spec;
3993 int err;
3994
3995 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3996 if (spec == NULL)
3997 return -ENOMEM;
3998
3999 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004000 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004001 spec->mono_nid = 0x19;
4002 spec->digbeep_nid = 0x21;
4003 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4004 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4005 spec->adc_nids = stac92hd83xxx_adc_nids;
4006 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4007 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4008 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4009 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4010
4011 spec->init = stac92hd83xxx_core_init;
4012 switch (codec->vendor_id) {
4013 case 0x111d7605:
4014 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4015 break;
4016 default:
4017 spec->num_pwrs--;
4018 spec->init++; /* switch to config #2 */
4019 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4020 }
4021
4022 spec->mixer = stac92hd83xxx_mixer;
4023 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4024 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4025 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4026 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4027 spec->dinput_mux = &stac92hd83xxx_dmux;
4028 spec->pin_nids = stac92hd83xxx_pin_nids;
4029 spec->board_config = snd_hda_check_board_config(codec,
4030 STAC_92HD83XXX_MODELS,
4031 stac92hd83xxx_models,
4032 stac92hd83xxx_cfg_tbl);
4033again:
4034 if (spec->board_config < 0) {
4035 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4036 " STAC92HD83XXX, using BIOS defaults\n");
4037 err = stac92xx_save_bios_config_regs(codec);
4038 if (err < 0) {
4039 stac92xx_free(codec);
4040 return err;
4041 }
4042 spec->pin_configs = spec->bios_pin_configs;
4043 } else {
4044 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4045 stac92xx_set_config_regs(codec);
4046 }
4047
4048 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4049 if (!err) {
4050 if (spec->board_config < 0) {
4051 printk(KERN_WARNING "hda_codec: No auto-config is "
4052 "available, default to model=ref\n");
4053 spec->board_config = STAC_92HD83XXX_REF;
4054 goto again;
4055 }
4056 err = -EINVAL;
4057 }
4058
4059 if (err < 0) {
4060 stac92xx_free(codec);
4061 return err;
4062 }
4063
4064 codec->patch_ops = stac92xx_patch_ops;
4065
4066 return 0;
4067}
4068
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004069#ifdef SND_HDA_NEEDS_RESUME
4070static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4071{
4072 struct sigmatel_spec *spec = codec->spec;
4073 int i;
4074 snd_hda_codec_write_cache(codec, codec->afg, 0,
4075 AC_VERB_SET_POWER_STATE, pwr);
4076
4077 msleep(1);
4078 for (i = 0; i < spec->num_adcs; i++) {
4079 snd_hda_codec_write_cache(codec,
4080 spec->adc_nids[i], 0,
4081 AC_VERB_SET_POWER_STATE, pwr);
4082 }
4083};
4084
4085static int stac92hd71xx_resume(struct hda_codec *codec)
4086{
4087 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4088 return stac92xx_resume(codec);
4089}
4090
4091static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4092{
4093 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4094 return 0;
4095};
4096
4097#endif
4098
4099static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4100 .build_controls = stac92xx_build_controls,
4101 .build_pcms = stac92xx_build_pcms,
4102 .init = stac92xx_init,
4103 .free = stac92xx_free,
4104 .unsol_event = stac92xx_unsol_event,
4105#ifdef SND_HDA_NEEDS_RESUME
4106 .resume = stac92hd71xx_resume,
4107 .suspend = stac92hd71xx_suspend,
4108#endif
4109};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004110
Matthew Ranostaye035b842007-11-06 11:53:55 +01004111static int patch_stac92hd71bxx(struct hda_codec *codec)
4112{
4113 struct sigmatel_spec *spec;
4114 int err = 0;
4115
4116 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4117 if (spec == NULL)
4118 return -ENOMEM;
4119
4120 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004121 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004122 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004123 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004124 spec->pin_nids = stac92hd71bxx_pin_nids;
4125 spec->board_config = snd_hda_check_board_config(codec,
4126 STAC_92HD71BXX_MODELS,
4127 stac92hd71bxx_models,
4128 stac92hd71bxx_cfg_tbl);
4129again:
4130 if (spec->board_config < 0) {
4131 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4132 " STAC92HD71BXX, using BIOS defaults\n");
4133 err = stac92xx_save_bios_config_regs(codec);
4134 if (err < 0) {
4135 stac92xx_free(codec);
4136 return err;
4137 }
4138 spec->pin_configs = spec->bios_pin_configs;
4139 } else {
4140 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4141 stac92xx_set_config_regs(codec);
4142 }
4143
Matthew Ranostay541eee82007-12-14 12:08:04 +01004144 switch (codec->vendor_id) {
4145 case 0x111d76b6: /* 4 Port without Analog Mixer */
4146 case 0x111d76b7:
4147 case 0x111d76b4: /* 6 Port without Analog Mixer */
4148 case 0x111d76b5:
4149 spec->mixer = stac92hd71bxx_mixer;
4150 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004151 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004152 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004153 case 0x111d7608: /* 5 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004154 if ((codec->revision_id & 0xf) == 0 ||
4155 (codec->revision_id & 0xf) == 1) {
4156#ifdef SND_HDA_NEEDS_RESUME
4157 codec->patch_ops = stac92hd71bxx_patch_ops;
4158#endif
4159 spec->stream_delay = 40; /* 40 milliseconds */
4160 }
4161
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004162 /* no output amps */
4163 spec->num_pwrs = 0;
4164 spec->mixer = stac92hd71bxx_analog_mixer;
4165
4166 /* disable VSW */
4167 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4168 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4169 break;
4170 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004171 if ((codec->revision_id & 0xf) == 1) {
4172#ifdef SND_HDA_NEEDS_RESUME
4173 codec->patch_ops = stac92hd71bxx_patch_ops;
4174#endif
4175 spec->stream_delay = 40; /* 40 milliseconds */
4176 }
4177
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004178 /* no output amps */
4179 spec->num_pwrs = 0;
4180 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004181 default:
4182 spec->mixer = stac92hd71bxx_analog_mixer;
4183 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004184 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004185 }
4186
4187 spec->aloopback_mask = 0x20;
4188 spec->aloopback_shift = 0;
4189
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004190 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004191 spec->gpio_mask = 0x01;
4192 spec->gpio_dir = 0x01;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004193 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004194
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004195 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004196 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004197 spec->mux_nids = stac92hd71bxx_mux_nids;
4198 spec->adc_nids = stac92hd71bxx_adc_nids;
4199 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004200 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004201 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004202 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004203
4204 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4205 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
4206 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004207 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004208 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004209
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004210 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004211 spec->multiout.hp_nid = 0x11;
4212 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
4213
4214 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4215 if (!err) {
4216 if (spec->board_config < 0) {
4217 printk(KERN_WARNING "hda_codec: No auto-config is "
4218 "available, default to model=ref\n");
4219 spec->board_config = STAC_92HD71BXX_REF;
4220 goto again;
4221 }
4222 err = -EINVAL;
4223 }
4224
4225 if (err < 0) {
4226 stac92xx_free(codec);
4227 return err;
4228 }
4229
Matthew Ranostaye035b842007-11-06 11:53:55 +01004230 return 0;
4231};
4232
Matt2f2f4252005-04-13 14:45:30 +02004233static int patch_stac922x(struct hda_codec *codec)
4234{
4235 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004236 int err;
Matt2f2f4252005-04-13 14:45:30 +02004237
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004238 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004239 if (spec == NULL)
4240 return -ENOMEM;
4241
4242 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004243 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004244 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004245 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4246 stac922x_models,
4247 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004248 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004249 spec->gpio_mask = spec->gpio_dir = 0x03;
4250 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004251 /* Intel Macs have all same PCI SSID, so we need to check
4252 * codec SSID to distinguish the exact models
4253 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004254 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004255 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004256
4257 case 0x106b0800:
4258 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004259 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004260 case 0x106b0600:
4261 case 0x106b0700:
4262 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004263 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004264 case 0x106b0e00:
4265 case 0x106b0f00:
4266 case 0x106b1600:
4267 case 0x106b1700:
4268 case 0x106b0200:
4269 case 0x106b1e00:
4270 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004271 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004272 case 0x106b1a00:
4273 case 0x00000100:
4274 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004275 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004276 case 0x106b0a00:
4277 case 0x106b2200:
4278 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004279 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004280 default:
4281 spec->board_config = STAC_INTEL_MAC_V3;
4282 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004283 }
4284 }
4285
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004286 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004287 if (spec->board_config < 0) {
4288 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4289 "using BIOS defaults\n");
4290 err = stac92xx_save_bios_config_regs(codec);
4291 if (err < 0) {
4292 stac92xx_free(codec);
4293 return err;
4294 }
4295 spec->pin_configs = spec->bios_pin_configs;
4296 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004297 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4298 stac92xx_set_config_regs(codec);
4299 }
Matt2f2f4252005-04-13 14:45:30 +02004300
Matt2f2f4252005-04-13 14:45:30 +02004301 spec->adc_nids = stac922x_adc_nids;
4302 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004303 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004304 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004305 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004306 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004307
4308 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004309 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004310
4311 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004312
Matt Porter3cc08dc2006-01-23 15:27:49 +01004313 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004314 if (!err) {
4315 if (spec->board_config < 0) {
4316 printk(KERN_WARNING "hda_codec: No auto-config is "
4317 "available, default to model=ref\n");
4318 spec->board_config = STAC_D945_REF;
4319 goto again;
4320 }
4321 err = -EINVAL;
4322 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004323 if (err < 0) {
4324 stac92xx_free(codec);
4325 return err;
4326 }
4327
4328 codec->patch_ops = stac92xx_patch_ops;
4329
Takashi Iwai807a46362007-05-29 19:01:37 +02004330 /* Fix Mux capture level; max to 2 */
4331 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4332 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4333 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4334 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4335 (0 << AC_AMPCAP_MUTE_SHIFT));
4336
Matt Porter3cc08dc2006-01-23 15:27:49 +01004337 return 0;
4338}
4339
4340static int patch_stac927x(struct hda_codec *codec)
4341{
4342 struct sigmatel_spec *spec;
4343 int err;
4344
4345 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4346 if (spec == NULL)
4347 return -ENOMEM;
4348
4349 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004350 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004351 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004352 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4353 stac927x_models,
4354 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004355 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004356 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4357 if (spec->board_config < 0)
4358 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4359 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004360 err = stac92xx_save_bios_config_regs(codec);
4361 if (err < 0) {
4362 stac92xx_free(codec);
4363 return err;
4364 }
4365 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004366 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004367 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4368 stac92xx_set_config_regs(codec);
4369 }
4370
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004371 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004372 spec->adc_nids = stac927x_adc_nids;
4373 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4374 spec->mux_nids = stac927x_mux_nids;
4375 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004376 spec->smux_nids = stac927x_smux_nids;
4377 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004378 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004379 spec->multiout.dac_nids = spec->dac_nids;
4380
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004381 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004382 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004383 case STAC_D965_5ST:
4384 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004385 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004386 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004387 spec->num_dmics = 0;
4388
Tobin Davis93ed1502006-09-01 21:03:12 +02004389 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004390 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004391 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004392 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004393 switch (codec->subsystem_id) {
4394 case 0x10280209:
4395 case 0x1028022e:
4396 /* correct the device field to SPDIF out */
4397 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4398 break;
4399 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004400 /* configure the analog microphone on some laptops */
4401 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004402 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004403 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004404 /* correct the front input jack as a mic */
4405 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4406 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004407 case STAC_DELL_3ST:
4408 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004409 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004410 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004411 spec->dmic_nids = stac927x_dmic_nids;
4412 spec->num_dmics = STAC927X_NUM_DMICS;
4413
Tobin Davis93ed1502006-09-01 21:03:12 +02004414 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004415 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004416 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004417 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004418 break;
4419 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004420 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004421 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004422 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004423 spec->num_dmics = 0;
4424
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004425 spec->init = stac927x_core_init;
4426 spec->mixer = stac927x_mixer;
4427 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004428
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004429 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004430 spec->aloopback_mask = 0x40;
4431 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004432
Matt Porter3cc08dc2006-01-23 15:27:49 +01004433 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004434 if (!err) {
4435 if (spec->board_config < 0) {
4436 printk(KERN_WARNING "hda_codec: No auto-config is "
4437 "available, default to model=ref\n");
4438 spec->board_config = STAC_D965_REF;
4439 goto again;
4440 }
4441 err = -EINVAL;
4442 }
Mattc7d4b2f2005-06-27 14:59:41 +02004443 if (err < 0) {
4444 stac92xx_free(codec);
4445 return err;
4446 }
Matt2f2f4252005-04-13 14:45:30 +02004447
4448 codec->patch_ops = stac92xx_patch_ops;
4449
Takashi Iwai52987652008-01-16 16:09:47 +01004450 /*
4451 * !!FIXME!!
4452 * The STAC927x seem to require fairly long delays for certain
4453 * command sequences. With too short delays (even if the answer
4454 * is set to RIRB properly), it results in the silence output
4455 * on some hardwares like Dell.
4456 *
4457 * The below flag enables the longer delay (see get_response
4458 * in hda_intel.c).
4459 */
4460 codec->bus->needs_damn_long_delay = 1;
4461
Matt2f2f4252005-04-13 14:45:30 +02004462 return 0;
4463}
4464
Matt Porterf3302a52006-07-31 12:49:34 +02004465static int patch_stac9205(struct hda_codec *codec)
4466{
4467 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004468 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004469
4470 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4471 if (spec == NULL)
4472 return -ENOMEM;
4473
4474 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004475 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004476 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004477 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4478 stac9205_models,
4479 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004480 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004481 if (spec->board_config < 0) {
4482 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4483 err = stac92xx_save_bios_config_regs(codec);
4484 if (err < 0) {
4485 stac92xx_free(codec);
4486 return err;
4487 }
4488 spec->pin_configs = spec->bios_pin_configs;
4489 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004490 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4491 stac92xx_set_config_regs(codec);
4492 }
4493
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004494 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004495 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004496 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004497 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004498 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004499 spec->smux_nids = stac9205_smux_nids;
4500 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004501 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004502 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004503 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004504 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004505 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004506
4507 spec->init = stac9205_core_init;
4508 spec->mixer = stac9205_mixer;
4509
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004510 spec->aloopback_mask = 0x40;
4511 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004512 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004513
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004514 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004515 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004516 /* Enable SPDIF in/out */
4517 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4518 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004519
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004520 /* Enable unsol response for GPIO4/Dock HP connection */
4521 snd_hda_codec_write(codec, codec->afg, 0,
4522 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4523 snd_hda_codec_write_cache(codec, codec->afg, 0,
4524 AC_VERB_SET_UNSOLICITED_ENABLE,
4525 (AC_USRSP_EN | STAC_HP_EVENT));
4526
4527 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004528 spec->eapd_mask = 0x01;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004529 spec->gpio_mask = 0x1b;
4530 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004531 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004532 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004533 */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004534 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004535 break;
4536 default:
4537 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004538 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004539 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004540 break;
4541 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004542
Matt Porterf3302a52006-07-31 12:49:34 +02004543 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004544 if (!err) {
4545 if (spec->board_config < 0) {
4546 printk(KERN_WARNING "hda_codec: No auto-config is "
4547 "available, default to model=ref\n");
4548 spec->board_config = STAC_9205_REF;
4549 goto again;
4550 }
4551 err = -EINVAL;
4552 }
Matt Porterf3302a52006-07-31 12:49:34 +02004553 if (err < 0) {
4554 stac92xx_free(codec);
4555 return err;
4556 }
4557
4558 codec->patch_ops = stac92xx_patch_ops;
4559
4560 return 0;
4561}
4562
Matt2f2f4252005-04-13 14:45:30 +02004563/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004564 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004565 */
4566
Guillaume Munch99ccc562006-08-16 19:35:12 +02004567/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004568static hda_nid_t vaio_dacs[] = { 0x2 };
4569#define VAIO_HP_DAC 0x5
4570static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4571static hda_nid_t vaio_mux_nids[] = { 0x15 };
4572
4573static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004574 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004575 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004576 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004577 { "Mic Jack", 0x1 },
4578 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004579 { "PCM", 0x3 },
4580 }
4581};
4582
4583static struct hda_verb vaio_init[] = {
4584 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004585 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004586 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4587 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4588 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4589 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004590 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004591 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4592 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4593 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4594 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4595 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4596 {}
4597};
4598
Guillaume Munch6d859062006-08-22 17:15:47 +02004599static struct hda_verb vaio_ar_init[] = {
4600 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4601 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4602 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4603 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4604/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4605 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004606 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004607 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4608 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4609/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4610 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4611 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4612 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4613 {}
4614};
4615
Takashi Iwaidb064e52006-03-16 16:04:58 +01004616/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004617static struct hda_bind_ctls vaio_bind_master_vol = {
4618 .ops = &snd_hda_bind_vol,
4619 .values = {
4620 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4621 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4622 0
4623 },
4624};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004625
4626/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004627static struct hda_bind_ctls vaio_bind_master_sw = {
4628 .ops = &snd_hda_bind_sw,
4629 .values = {
4630 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4631 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4632 0,
4633 },
4634};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004635
4636static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004637 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4638 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004639 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4640 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4641 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4642 {
4643 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4644 .name = "Capture Source",
4645 .count = 1,
4646 .info = stac92xx_mux_enum_info,
4647 .get = stac92xx_mux_enum_get,
4648 .put = stac92xx_mux_enum_put,
4649 },
4650 {}
4651};
4652
Guillaume Munch6d859062006-08-22 17:15:47 +02004653static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004654 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4655 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004656 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4657 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4658 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4659 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4660 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4661 {
4662 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4663 .name = "Capture Source",
4664 .count = 1,
4665 .info = stac92xx_mux_enum_info,
4666 .get = stac92xx_mux_enum_get,
4667 .put = stac92xx_mux_enum_put,
4668 },
4669 {}
4670};
4671
4672static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004673 .build_controls = stac92xx_build_controls,
4674 .build_pcms = stac92xx_build_pcms,
4675 .init = stac92xx_init,
4676 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004677#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004678 .resume = stac92xx_resume,
4679#endif
4680};
4681
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004682static int stac9872_vaio_init(struct hda_codec *codec)
4683{
4684 int err;
4685
4686 err = stac92xx_init(codec);
4687 if (err < 0)
4688 return err;
4689 if (codec->patch_ops.unsol_event)
4690 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4691 return 0;
4692}
4693
4694static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4695{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004696 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004697 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4698 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4699 } else {
4700 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4701 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4702 }
4703}
4704
4705static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4706{
4707 switch (res >> 26) {
4708 case STAC_HP_EVENT:
4709 stac9872_vaio_hp_detect(codec, res);
4710 break;
4711 }
4712}
4713
4714static struct hda_codec_ops stac9872_vaio_patch_ops = {
4715 .build_controls = stac92xx_build_controls,
4716 .build_pcms = stac92xx_build_pcms,
4717 .init = stac9872_vaio_init,
4718 .free = stac92xx_free,
4719 .unsol_event = stac9872_vaio_unsol_event,
4720#ifdef CONFIG_PM
4721 .resume = stac92xx_resume,
4722#endif
4723};
4724
Guillaume Munch6d859062006-08-22 17:15:47 +02004725enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4726 CXD9872RD_VAIO,
4727 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4728 STAC9872AK_VAIO,
4729 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4730 STAC9872K_VAIO,
4731 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004732 CXD9872AKD_VAIO,
4733 STAC_9872_MODELS,
4734};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004735
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004736static const char *stac9872_models[STAC_9872_MODELS] = {
4737 [CXD9872RD_VAIO] = "vaio",
4738 [CXD9872AKD_VAIO] = "vaio-ar",
4739};
4740
4741static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4742 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4743 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4744 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004745 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004746 {}
4747};
4748
Guillaume Munch6d859062006-08-22 17:15:47 +02004749static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004750{
4751 struct sigmatel_spec *spec;
4752 int board_config;
4753
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004754 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4755 stac9872_models,
4756 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004757 if (board_config < 0)
4758 /* unknown config, let generic-parser do its job... */
4759 return snd_hda_parse_generic_codec(codec);
4760
4761 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4762 if (spec == NULL)
4763 return -ENOMEM;
4764
4765 codec->spec = spec;
4766 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004767 case CXD9872RD_VAIO:
4768 case STAC9872AK_VAIO:
4769 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004770 spec->mixer = vaio_mixer;
4771 spec->init = vaio_init;
4772 spec->multiout.max_channels = 2;
4773 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4774 spec->multiout.dac_nids = vaio_dacs;
4775 spec->multiout.hp_nid = VAIO_HP_DAC;
4776 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4777 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004778 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004779 spec->input_mux = &vaio_mux;
4780 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004781 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004782 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004783
4784 case CXD9872AKD_VAIO:
4785 spec->mixer = vaio_ar_mixer;
4786 spec->init = vaio_ar_init;
4787 spec->multiout.max_channels = 2;
4788 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4789 spec->multiout.dac_nids = vaio_dacs;
4790 spec->multiout.hp_nid = VAIO_HP_DAC;
4791 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004792 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004793 spec->adc_nids = vaio_adcs;
4794 spec->input_mux = &vaio_mux;
4795 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004796 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004797 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004798 }
4799
Takashi Iwaidb064e52006-03-16 16:04:58 +01004800 return 0;
4801}
4802
4803
4804/*
Matt2f2f4252005-04-13 14:45:30 +02004805 * patch entries
4806 */
4807struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4808 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4809 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4810 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4811 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4812 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4813 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4814 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004815 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4816 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4817 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4818 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4819 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4820 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004821 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4822 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4823 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4824 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4825 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4826 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4827 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4828 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4829 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4830 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004831 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4832 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4833 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4834 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4835 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4836 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02004837 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
4838 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004839 /* The following does not take into account .id=0x83847661 when subsys =
4840 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4841 * currently not fully supported.
4842 */
4843 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4844 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4845 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004846 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4847 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4848 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4849 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4850 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4851 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4852 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4853 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004854 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004855 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
4856 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004857 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01004858 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4859 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004860 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004861 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4862 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4863 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4864 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4865 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4866 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4867 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4868 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004869 {} /* terminator */
4870};