blob: 9744ae31dc73e90c675e6d23d01e0c7f5ef6964d [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 Ranostay6a14f582008-09-12 12:02:30 -040083 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010084 STAC_92HD71BXX_MODELS
85};
86
87enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010088 STAC_925x_REF,
89 STAC_M2_2,
90 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020091 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010092 STAC_925x_MODELS
93};
94
95enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010096 STAC_D945_REF,
97 STAC_D945GTP3,
98 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020099 STAC_INTEL_MAC_V1,
100 STAC_INTEL_MAC_V2,
101 STAC_INTEL_MAC_V3,
102 STAC_INTEL_MAC_V4,
103 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800104 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
105 * is given, one of the above models will be
106 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200107 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100108 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100109 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100110 STAC_MACBOOK_PRO_V1,
111 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200112 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200113 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300114 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200115 STAC_922X_DELL_D81,
116 STAC_922X_DELL_D82,
117 STAC_922X_DELL_M81,
118 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100119 STAC_922X_MODELS
120};
121
122enum {
123 STAC_D965_REF,
124 STAC_D965_3ST,
125 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200126 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100127 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100128 STAC_927X_MODELS
129};
Matt Porter403d1942005-11-29 15:00:51 +0100130
Matt2f2f4252005-04-13 14:45:30 +0200131struct sigmatel_spec {
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100132 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200133 unsigned int num_mixers;
134
Matt Porter403d1942005-11-29 15:00:51 +0100135 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200136 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100137 unsigned int line_switch: 1;
138 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100139 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100140 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200141
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100142 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200143 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100144 unsigned int gpio_mask;
145 unsigned int gpio_dir;
146 unsigned int gpio_data;
147 unsigned int gpio_mute;
148
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200149 /* stream */
150 unsigned int stream_delay;
151
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100152 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100153 unsigned char aloopback_mask;
154 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200155
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100156 /* power management */
157 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200158 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100159 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100160 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100161
Matt2f2f4252005-04-13 14:45:30 +0200162 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100163 struct hda_input_mux *mono_mux;
164 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200165 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100166 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200167
168 /* capture */
169 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200170 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200171 hda_nid_t *mux_nids;
172 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200173 hda_nid_t *dmic_nids;
174 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100175 hda_nid_t *dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +0100176 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200177 hda_nid_t *smux_nids;
178 unsigned int num_smuxes;
179
Mattdabbed62005-06-14 10:19:34 +0200180 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100181 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200182 hda_nid_t anabeep_nid;
183 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200184
Matt2f2f4252005-04-13 14:45:30 +0200185 /* pin widgets */
186 hda_nid_t *pin_nids;
187 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200188 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200189 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200190
191 /* codec specific stuff */
192 struct hda_verb *init;
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100193 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200194
195 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200196 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100197 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200198 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100199 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200200 struct hda_input_mux *sinput_mux;
201 unsigned int cur_smux[2];
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200202 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200203
Matt Porter403d1942005-11-29 15:00:51 +0100204 /* i/o switches */
205 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200206 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200207 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200208 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200209
Mattc7d4b2f2005-06-27 14:59:41 +0200210 struct hda_pcm pcm_rec[2]; /* PCM information */
211
212 /* dynamic controls and input_mux */
213 struct auto_pin_cfg autocfg;
214 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100215 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200216 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200217 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200218 struct hda_input_mux private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100219 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200220};
221
222static hda_nid_t stac9200_adc_nids[1] = {
223 0x03,
224};
225
226static hda_nid_t stac9200_mux_nids[1] = {
227 0x0c,
228};
229
230static hda_nid_t stac9200_dac_nids[1] = {
231 0x02,
232};
233
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100234static hda_nid_t stac92hd73xx_pwr_nids[8] = {
235 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
236 0x0f, 0x10, 0x11
237};
238
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400239static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
240 0x26, 0,
241};
242
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100243static hda_nid_t stac92hd73xx_adc_nids[2] = {
244 0x1a, 0x1b
245};
246
247#define STAC92HD73XX_NUM_DMICS 2
248static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
249 0x13, 0x14, 0
250};
251
252#define STAC92HD73_DAC_COUNT 5
253static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
254 0x15, 0x16, 0x17, 0x18, 0x19,
255};
256
257static hda_nid_t stac92hd73xx_mux_nids[4] = {
258 0x28, 0x29, 0x2a, 0x2b,
259};
260
261static hda_nid_t stac92hd73xx_dmux_nids[2] = {
262 0x20, 0x21,
263};
264
Matthew Ranostayd9737752008-09-07 12:03:41 +0200265static hda_nid_t stac92hd73xx_smux_nids[2] = {
266 0x22, 0x23,
267};
268
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200269#define STAC92HD83XXX_NUM_DMICS 2
270static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
271 0x11, 0x12, 0
272};
273
274#define STAC92HD81_DAC_COUNT 2
275#define STAC92HD83_DAC_COUNT 3
276static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
277 0x13, 0x14, 0x22,
278};
279
280static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
281 0x17, 0x18,
282};
283
284static hda_nid_t stac92hd83xxx_adc_nids[2] = {
285 0x15, 0x16,
286};
287
288static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
289 0xa, 0xb, 0xd, 0xe,
290};
291
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400292static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
293 0x1e, 0,
294};
295
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200296static unsigned int stac92hd83xxx_pwr_mapping[4] = {
297 0x03, 0x0c, 0x10, 0x40,
298};
299
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100300static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
301 0x0a, 0x0d, 0x0f
302};
303
Matthew Ranostaye035b842007-11-06 11:53:55 +0100304static hda_nid_t stac92hd71bxx_adc_nids[2] = {
305 0x12, 0x13,
306};
307
308static hda_nid_t stac92hd71bxx_mux_nids[2] = {
309 0x1a, 0x1b
310};
311
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100312static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
313 0x1c,
314};
315
Matthew Ranostayd9737752008-09-07 12:03:41 +0200316static hda_nid_t stac92hd71bxx_smux_nids[2] = {
317 0x24, 0x25,
318};
319
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100320static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100321 0x10, /*0x11, */
322};
323
324#define STAC92HD71BXX_NUM_DMICS 2
325static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
326 0x18, 0x19, 0
327};
328
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400329static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
330 0x22, 0
331};
332
Tobin Davis8e21c342007-01-08 11:04:17 +0100333static hda_nid_t stac925x_adc_nids[1] = {
334 0x03,
335};
336
337static hda_nid_t stac925x_mux_nids[1] = {
338 0x0f,
339};
340
341static hda_nid_t stac925x_dac_nids[1] = {
342 0x02,
343};
344
Takashi Iwaif6e98522007-10-16 14:27:04 +0200345#define STAC925X_NUM_DMICS 1
346static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
347 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200348};
349
Takashi Iwai16970552007-12-18 18:05:52 +0100350static hda_nid_t stac925x_dmux_nids[1] = {
351 0x14,
352};
353
Matt2f2f4252005-04-13 14:45:30 +0200354static hda_nid_t stac922x_adc_nids[2] = {
355 0x06, 0x07,
356};
357
358static hda_nid_t stac922x_mux_nids[2] = {
359 0x12, 0x13,
360};
361
Matt Porter3cc08dc2006-01-23 15:27:49 +0100362static hda_nid_t stac927x_adc_nids[3] = {
363 0x07, 0x08, 0x09
364};
365
366static hda_nid_t stac927x_mux_nids[3] = {
367 0x15, 0x16, 0x17
368};
369
Matthew Ranostayd9737752008-09-07 12:03:41 +0200370static hda_nid_t stac927x_smux_nids[1] = {
371 0x21,
372};
373
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100374static hda_nid_t stac927x_dac_nids[6] = {
375 0x02, 0x03, 0x04, 0x05, 0x06, 0
376};
377
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100378static hda_nid_t stac927x_dmux_nids[1] = {
379 0x1b,
380};
381
Matthew Ranostay7f168592007-10-18 17:38:17 +0200382#define STAC927X_NUM_DMICS 2
383static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
384 0x13, 0x14, 0
385};
386
Matt Porterf3302a52006-07-31 12:49:34 +0200387static hda_nid_t stac9205_adc_nids[2] = {
388 0x12, 0x13
389};
390
391static hda_nid_t stac9205_mux_nids[2] = {
392 0x19, 0x1a
393};
394
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100395static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai16970552007-12-18 18:05:52 +0100396 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100397};
398
Matthew Ranostayd9737752008-09-07 12:03:41 +0200399static hda_nid_t stac9205_smux_nids[1] = {
400 0x21,
401};
402
Takashi Iwaif6e98522007-10-16 14:27:04 +0200403#define STAC9205_NUM_DMICS 2
404static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
405 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200406};
407
Mattc7d4b2f2005-06-27 14:59:41 +0200408static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200409 0x08, 0x09, 0x0d, 0x0e,
410 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200411};
412
Tobin Davis8e21c342007-01-08 11:04:17 +0100413static hda_nid_t stac925x_pin_nids[8] = {
414 0x07, 0x08, 0x0a, 0x0b,
415 0x0c, 0x0d, 0x10, 0x11,
416};
417
Matt2f2f4252005-04-13 14:45:30 +0200418static hda_nid_t stac922x_pin_nids[10] = {
419 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
420 0x0f, 0x10, 0x11, 0x15, 0x1b,
421};
422
Matthew Ranostaya7662642008-02-21 07:51:14 +0100423static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100424 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
425 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200426 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100427};
428
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200429static hda_nid_t stac92hd83xxx_pin_nids[14] = {
430 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
431 0x0f, 0x10, 0x11, 0x12, 0x13,
432 0x1d, 0x1e, 0x1f, 0x20
433};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400434static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100435 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
436 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400437 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100438};
439
Matt Porter3cc08dc2006-01-23 15:27:49 +0100440static hda_nid_t stac927x_pin_nids[14] = {
441 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
442 0x0f, 0x10, 0x11, 0x12, 0x13,
443 0x14, 0x21, 0x22, 0x23,
444};
445
Matt Porterf3302a52006-07-31 12:49:34 +0200446static hda_nid_t stac9205_pin_nids[12] = {
447 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
448 0x0f, 0x14, 0x16, 0x17, 0x18,
449 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200450};
451
Matt Porter8b657272006-10-26 17:12:59 +0200452static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
453 struct snd_ctl_elem_info *uinfo)
454{
455 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
456 struct sigmatel_spec *spec = codec->spec;
457 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
458}
459
460static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
461 struct snd_ctl_elem_value *ucontrol)
462{
463 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
464 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100465 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200466
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100467 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200468 return 0;
469}
470
471static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
472 struct snd_ctl_elem_value *ucontrol)
473{
474 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
475 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100476 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200477
478 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100479 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200480}
481
Matthew Ranostayd9737752008-09-07 12:03:41 +0200482static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
483 struct snd_ctl_elem_info *uinfo)
484{
485 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
486 struct sigmatel_spec *spec = codec->spec;
487 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
488}
489
490static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
491 struct snd_ctl_elem_value *ucontrol)
492{
493 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
494 struct sigmatel_spec *spec = codec->spec;
495 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
496
497 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
498 return 0;
499}
500
501static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
502 struct snd_ctl_elem_value *ucontrol)
503{
504 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
505 struct sigmatel_spec *spec = codec->spec;
506 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
507
508 return snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
509 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
510}
511
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100512static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200513{
514 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
515 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200516 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200517}
518
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100519static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200520{
521 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
522 struct sigmatel_spec *spec = codec->spec;
523 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
524
525 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
526 return 0;
527}
528
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100529static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200530{
531 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
532 struct sigmatel_spec *spec = codec->spec;
533 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
534
Mattc7d4b2f2005-06-27 14:59:41 +0200535 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200536 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
537}
538
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100539static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
540 struct snd_ctl_elem_info *uinfo)
541{
542 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
543 struct sigmatel_spec *spec = codec->spec;
544 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
545}
546
547static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
548 struct snd_ctl_elem_value *ucontrol)
549{
550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
551 struct sigmatel_spec *spec = codec->spec;
552
553 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
554 return 0;
555}
556
557static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
558 struct snd_ctl_elem_value *ucontrol)
559{
560 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
561 struct sigmatel_spec *spec = codec->spec;
562
563 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
564 spec->mono_nid, &spec->cur_mmux);
565}
566
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200567#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
568
569static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
570 struct snd_ctl_elem_value *ucontrol)
571{
572 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100573 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200574 struct sigmatel_spec *spec = codec->spec;
575
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100576 ucontrol->value.integer.value[0] = !!(spec->aloopback &
577 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200578 return 0;
579}
580
581static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
582 struct snd_ctl_elem_value *ucontrol)
583{
584 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
585 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100586 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200587 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100588 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200589
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100590 idx_val = spec->aloopback_mask << idx;
591 if (ucontrol->value.integer.value[0])
592 val = spec->aloopback | idx_val;
593 else
594 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100595 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200596 return 0;
597
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100598 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200599
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100600 /* Only return the bits defined by the shift value of the
601 * first two bytes of the mask
602 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200603 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100604 kcontrol->private_value & 0xFFFF, 0x0);
605 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200606
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100607 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200608 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100609 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200610 } else {
611 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100612 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200613 }
614
615 snd_hda_codec_write_cache(codec, codec->afg, 0,
616 kcontrol->private_value >> 16, dac_mode);
617
618 return 1;
619}
620
Mattc7d4b2f2005-06-27 14:59:41 +0200621static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200622 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200623 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200624 {}
625};
626
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200627static struct hda_verb stac9200_eapd_init[] = {
628 /* set dac0mux for dac converter */
629 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
630 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
631 {}
632};
633
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100634static struct hda_verb stac92hd73xx_6ch_core_init[] = {
635 /* set master volume and direct control */
636 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
637 /* setup audio connections */
638 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
639 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
640 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
641 /* setup adcs to point to mixer */
642 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
643 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100644 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
645 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
646 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
647 /* setup import muxs */
648 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
649 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
650 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
651 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
652 {}
653};
654
Matthew Ranostayd654a662008-03-14 08:46:51 +0100655static struct hda_verb dell_eq_core_init[] = {
656 /* set master volume to max value without distortion
657 * and direct control */
658 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
659 /* setup audio connections */
660 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
661 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
662 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
663 /* setup adcs to point to mixer */
664 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
665 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
666 /* setup import muxs */
667 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
668 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
669 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
670 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
671 {}
672};
673
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100674static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay20f5f952008-09-01 08:17:56 +0200675 /* set master volume to max value without distortion
676 * and direct control */
677 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100678 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100679 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
680 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100681 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
682 /* setup adcs to point to mixer */
683 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
684 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
685 /* setup import muxs */
686 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
687 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
688 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
689 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
690 {}
691};
692
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100693static struct hda_verb stac92hd73xx_8ch_core_init[] = {
694 /* set master volume and direct control */
695 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
696 /* setup audio connections */
697 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
698 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
699 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
700 /* connect hp ports to dac3 */
701 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
702 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
703 /* setup adcs to point to mixer */
704 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
705 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100706 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
707 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
708 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
709 /* setup import muxs */
710 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
711 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
712 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
713 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
714 {}
715};
716
717static struct hda_verb stac92hd73xx_10ch_core_init[] = {
718 /* set master volume and direct control */
719 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
720 /* setup audio connections */
721 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
722 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
723 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
724 /* dac3 is connected to import3 mux */
725 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
726 /* connect hp ports to dac4 */
727 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
728 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
729 /* setup adcs to point to mixer */
730 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
731 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
733 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
734 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
735 /* setup import muxs */
736 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
737 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
738 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
739 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
740 {}
741};
742
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200743static struct hda_verb stac92hd83xxx_core_init[] = {
744 /* start of config #1 */
745 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
746
747 /* start of config #2 */
748 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
749 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
750 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
751
752 /* power state controls amps */
753 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
754};
755
Matthew Ranostaye035b842007-11-06 11:53:55 +0100756static struct hda_verb stac92hd71bxx_core_init[] = {
757 /* set master volume and direct control */
758 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
759 /* connect headphone jack to dac1 */
760 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100761 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
762 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
763 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
764 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
765 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100766};
767
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200768#define HD_DISABLE_PORTF 3
Matthew Ranostay541eee82007-12-14 12:08:04 +0100769static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200770 /* start of config #1 */
771
772 /* connect port 0f to audio mixer */
773 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
774 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
775 /* unmute right and left channels for node 0x0f */
776 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
777 /* start of config #2 */
778
Matthew Ranostay541eee82007-12-14 12:08:04 +0100779 /* set master volume and direct control */
780 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
781 /* connect headphone jack to dac1 */
782 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200783 /* connect port 0d to audio mixer */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100784 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100785 /* unmute dac0 input in audio mixer */
786 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200787 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100788 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
789 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100790 {}
791};
792
Tobin Davis8e21c342007-01-08 11:04:17 +0100793static struct hda_verb stac925x_core_init[] = {
794 /* set dac0mux for dac converter */
795 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
796 {}
797};
798
Mattc7d4b2f2005-06-27 14:59:41 +0200799static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200800 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200801 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200802 {}
803};
804
Tobin Davis93ed1502006-09-01 21:03:12 +0200805static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200806 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200807 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200808 /* unmute node 0x1b */
809 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
810 /* select node 0x03 as DAC */
811 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
812 {}
813};
814
Matt Porter3cc08dc2006-01-23 15:27:49 +0100815static struct hda_verb stac927x_core_init[] = {
816 /* set master volume and direct control */
817 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200818 /* enable analog pc beep path */
819 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100820 {}
821};
822
Matt Porterf3302a52006-07-31 12:49:34 +0200823static struct hda_verb stac9205_core_init[] = {
824 /* set master volume and direct control */
825 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200826 /* enable analog pc beep path */
827 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200828 {}
829};
830
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100831#define STAC_MONO_MUX \
832 { \
833 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
834 .name = "Mono Mux", \
835 .count = 1, \
836 .info = stac92xx_mono_mux_enum_info, \
837 .get = stac92xx_mono_mux_enum_get, \
838 .put = stac92xx_mono_mux_enum_put, \
839 }
840
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200841#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200842 { \
843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
844 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200845 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200846 .info = stac92xx_mux_enum_info, \
847 .get = stac92xx_mux_enum_get, \
848 .put = stac92xx_mux_enum_put, \
849 }
850
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100851#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200852 { \
853 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
854 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100855 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200856 .info = stac92xx_aloopback_info, \
857 .get = stac92xx_aloopback_get, \
858 .put = stac92xx_aloopback_put, \
859 .private_value = verb_read | (verb_write << 16), \
860 }
861
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100862static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200863 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
864 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200865 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200866 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
867 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200868 { } /* end */
869};
870
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100871static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100872 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
873
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100874 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
875 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
876
877 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
878 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
879
880 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
881 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
882
883 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
884 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
885
886 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
887 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
888
889 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
890 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
891
892 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
893 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
894 { } /* end */
895};
896
897static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100898 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
899
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100900 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
901 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
902
903 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
904 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
905
906 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
907 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
908
909 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
910 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
911
912 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
913 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
914
915 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
916 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
917
918 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
919 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
920 { } /* end */
921};
922
923static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100924 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
925
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100926 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
927 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
928
929 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
930 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
931
932 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
933 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
934
935 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
936 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
937
938 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
939 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
940
941 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
942 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
943
944 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
945 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
946 { } /* end */
947};
948
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200949
950static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
951 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
952 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
953
954 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
955 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
956
957 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
958 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
959
960 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
961 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
962
963 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
964 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
965
966 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
967 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
968
969 /*
970 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
971 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
972 */
973 { } /* end */
974};
975
Matthew Ranostay541eee82007-12-14 12:08:04 +0100976static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100977 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100978
Matthew Ranostay9b359472007-11-07 13:03:12 +0100979 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
980 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +0100981
982 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
983 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200984 /* analog pc-beep replaced with digital beep support */
985 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200986 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
987 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200988 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200989
Matthew Ranostay9b359472007-11-07 13:03:12 +0100990 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
991 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100992 { } /* end */
993};
994
Matthew Ranostay541eee82007-12-14 12:08:04 +0100995static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100996 STAC_INPUT_SOURCE(2),
997 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
998
Matthew Ranostay541eee82007-12-14 12:08:04 +0100999 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1000 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001001
1002 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1003 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001004 { } /* end */
1005};
1006
Tobin Davis8e21c342007-01-08 11:04:17 +01001007static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001008 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001009 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001010 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001011 { } /* end */
1012};
1013
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001014static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001015 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001016 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001017
1018 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1019 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001020
1021 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1022 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001023 { } /* end */
1024};
1025
1026/* This needs to be generated dynamically based on sequence */
1027static struct snd_kcontrol_new stac922x_mixer[] = {
1028 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001029 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1030 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001031
1032 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1033 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001034 { } /* end */
1035};
1036
1037
1038static struct snd_kcontrol_new stac927x_mixer[] = {
1039 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001040 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001041
1042 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1043 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001044
1045 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1046 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001047
1048 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1049 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001050 { } /* end */
1051};
1052
Takashi Iwai16970552007-12-18 18:05:52 +01001053static struct snd_kcontrol_new stac_dmux_mixer = {
1054 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1055 .name = "Digital Input Source",
1056 /* count set later */
1057 .info = stac92xx_dmux_enum_info,
1058 .get = stac92xx_dmux_enum_get,
1059 .put = stac92xx_dmux_enum_put,
1060};
1061
Matthew Ranostayd9737752008-09-07 12:03:41 +02001062static struct snd_kcontrol_new stac_smux_mixer = {
1063 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001064 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001065 /* count set later */
1066 .info = stac92xx_smux_enum_info,
1067 .get = stac92xx_smux_enum_get,
1068 .put = stac92xx_smux_enum_put,
1069};
1070
Takashi Iwai2134ea42008-01-10 16:53:55 +01001071static const char *slave_vols[] = {
1072 "Front Playback Volume",
1073 "Surround Playback Volume",
1074 "Center Playback Volume",
1075 "LFE Playback Volume",
1076 "Side Playback Volume",
1077 "Headphone Playback Volume",
1078 "Headphone Playback Volume",
1079 "Speaker Playback Volume",
1080 "External Speaker Playback Volume",
1081 "Speaker2 Playback Volume",
1082 NULL
1083};
1084
1085static const char *slave_sws[] = {
1086 "Front Playback Switch",
1087 "Surround Playback Switch",
1088 "Center Playback Switch",
1089 "LFE Playback Switch",
1090 "Side Playback Switch",
1091 "Headphone Playback Switch",
1092 "Headphone Playback Switch",
1093 "Speaker Playback Switch",
1094 "External Speaker Playback Switch",
1095 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001096 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001097 NULL
1098};
1099
Matt2f2f4252005-04-13 14:45:30 +02001100static int stac92xx_build_controls(struct hda_codec *codec)
1101{
1102 struct sigmatel_spec *spec = codec->spec;
1103 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001104 int i;
Matt2f2f4252005-04-13 14:45:30 +02001105
1106 err = snd_hda_add_new_ctls(codec, spec->mixer);
1107 if (err < 0)
1108 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001109
1110 for (i = 0; i < spec->num_mixers; i++) {
1111 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1112 if (err < 0)
1113 return err;
1114 }
Takashi Iwai16970552007-12-18 18:05:52 +01001115 if (spec->num_dmuxes > 0) {
1116 stac_dmux_mixer.count = spec->num_dmuxes;
1117 err = snd_ctl_add(codec->bus->card,
1118 snd_ctl_new1(&stac_dmux_mixer, codec));
1119 if (err < 0)
1120 return err;
1121 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001122 if (spec->num_smuxes > 0) {
1123 stac_smux_mixer.count = spec->num_smuxes;
1124 err = snd_ctl_add(codec->bus->card,
1125 snd_ctl_new1(&stac_smux_mixer, codec));
1126 if (err < 0)
1127 return err;
1128 }
Mattc7d4b2f2005-06-27 14:59:41 +02001129
Mattdabbed62005-06-14 10:19:34 +02001130 if (spec->multiout.dig_out_nid) {
1131 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1132 if (err < 0)
1133 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001134 err = snd_hda_create_spdif_share_sw(codec,
1135 &spec->multiout);
1136 if (err < 0)
1137 return err;
1138 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001139 }
1140 if (spec->dig_in_nid) {
1141 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1142 if (err < 0)
1143 return err;
1144 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001145
1146 /* if we have no master control, let's create it */
1147 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001148 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001149 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001150 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001151 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001152 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001153 if (err < 0)
1154 return err;
1155 }
1156 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1157 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1158 NULL, slave_sws);
1159 if (err < 0)
1160 return err;
1161 }
1162
Mattdabbed62005-06-14 10:19:34 +02001163 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001164}
1165
Matt Porter403d1942005-11-29 15:00:51 +01001166static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001167 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001168 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1169};
1170
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001171/*
1172 STAC 9200 pin configs for
1173 102801A8
1174 102801DE
1175 102801E8
1176*/
1177static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001178 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1179 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001180};
1181
1182/*
1183 STAC 9200 pin configs for
1184 102801C0
1185 102801C1
1186*/
1187static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001188 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1189 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001190};
1191
1192/*
1193 STAC 9200 pin configs for
1194 102801C4 (Dell Dimension E310)
1195 102801C5
1196 102801C7
1197 102801D9
1198 102801DA
1199 102801E3
1200*/
1201static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001202 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1203 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001204};
1205
1206
1207/*
1208 STAC 9200-32 pin configs for
1209 102801B5 (Dell Inspiron 630m)
1210 102801D8 (Dell Inspiron 640m)
1211*/
1212static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001213 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1214 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001215};
1216
1217/*
1218 STAC 9200-32 pin configs for
1219 102801C2 (Dell Latitude D620)
1220 102801C8
1221 102801CC (Dell Latitude D820)
1222 102801D4
1223 102801D6
1224*/
1225static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001226 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1227 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001228};
1229
1230/*
1231 STAC 9200-32 pin configs for
1232 102801CE (Dell XPS M1710)
1233 102801CF (Dell Precision M90)
1234*/
1235static unsigned int dell9200_m23_pin_configs[8] = {
1236 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1237 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1238};
1239
1240/*
1241 STAC 9200-32 pin configs for
1242 102801C9
1243 102801CA
1244 102801CB (Dell Latitude 120L)
1245 102801D3
1246*/
1247static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001248 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1249 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001250};
1251
1252/*
1253 STAC 9200-32 pin configs for
1254 102801BD (Dell Inspiron E1505n)
1255 102801EE
1256 102801EF
1257*/
1258static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001259 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1260 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001261};
1262
1263/*
1264 STAC 9200-32 pin configs for
1265 102801F5 (Dell Inspiron 1501)
1266 102801F6
1267*/
1268static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001269 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1270 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001271};
1272
1273/*
1274 STAC 9200-32
1275 102801CD (Dell Inspiron E1705/9400)
1276*/
1277static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001278 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1279 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001280};
1281
Tobin Davisbf277782008-02-03 20:31:47 +01001282static unsigned int oqo9200_pin_configs[8] = {
1283 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1284 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1285};
1286
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001287
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001288static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1289 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001290 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001291 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1292 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1293 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1294 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1295 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1296 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1297 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1298 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1299 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1300 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001301 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001302};
1303
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001304static const char *stac9200_models[STAC_9200_MODELS] = {
1305 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001306 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001307 [STAC_9200_DELL_D21] = "dell-d21",
1308 [STAC_9200_DELL_D22] = "dell-d22",
1309 [STAC_9200_DELL_D23] = "dell-d23",
1310 [STAC_9200_DELL_M21] = "dell-m21",
1311 [STAC_9200_DELL_M22] = "dell-m22",
1312 [STAC_9200_DELL_M23] = "dell-m23",
1313 [STAC_9200_DELL_M24] = "dell-m24",
1314 [STAC_9200_DELL_M25] = "dell-m25",
1315 [STAC_9200_DELL_M26] = "dell-m26",
1316 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001317 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001318 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001319};
1320
1321static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1322 /* SigmaTel reference board */
1323 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1324 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001325 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001326 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1327 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001328 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001329 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1330 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1331 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1332 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1333 "unknown Dell", STAC_9200_DELL_D22),
1334 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1335 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001336 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001337 "Dell Latitude D620", STAC_9200_DELL_M22),
1338 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1339 "unknown Dell", STAC_9200_DELL_D23),
1340 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1341 "unknown Dell", STAC_9200_DELL_D23),
1342 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1343 "unknown Dell", STAC_9200_DELL_M22),
1344 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1345 "unknown Dell", STAC_9200_DELL_M24),
1346 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1347 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001348 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001349 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001350 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001351 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001352 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001353 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001354 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001355 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001356 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001357 "Dell Precision M90", STAC_9200_DELL_M23),
1358 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1359 "unknown Dell", STAC_9200_DELL_M22),
1360 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1361 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001362 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001363 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001364 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001365 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1366 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1367 "unknown Dell", STAC_9200_DELL_D23),
1368 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1369 "unknown Dell", STAC_9200_DELL_D23),
1370 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1371 "unknown Dell", STAC_9200_DELL_D21),
1372 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1373 "unknown Dell", STAC_9200_DELL_D23),
1374 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1375 "unknown Dell", STAC_9200_DELL_D21),
1376 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1377 "unknown Dell", STAC_9200_DELL_M25),
1378 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1379 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001380 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001381 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1382 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1383 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001384 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001385 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001386 /* Gateway machines needs EAPD to be set on resume */
1387 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1388 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1389 STAC_9200_GATEWAY),
1390 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1391 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001392 /* OQO Mobile */
1393 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001394 {} /* terminator */
1395};
1396
Tobin Davis8e21c342007-01-08 11:04:17 +01001397static unsigned int ref925x_pin_configs[8] = {
1398 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001399 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001400};
1401
1402static unsigned int stac925x_MA6_pin_configs[8] = {
1403 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1404 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1405};
1406
Tobin Davis2c11f952007-05-17 09:36:34 +02001407static unsigned int stac925x_PA6_pin_configs[8] = {
1408 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1409 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1410};
1411
Tobin Davis8e21c342007-01-08 11:04:17 +01001412static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001413 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1414 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001415};
1416
1417static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1418 [STAC_REF] = ref925x_pin_configs,
1419 [STAC_M2_2] = stac925xM2_2_pin_configs,
1420 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001421 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001422};
1423
1424static const char *stac925x_models[STAC_925x_MODELS] = {
1425 [STAC_REF] = "ref",
1426 [STAC_M2_2] = "m2-2",
1427 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001428 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001429};
1430
1431static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1432 /* SigmaTel reference board */
1433 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001434 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001435 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1436 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1437 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001438 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001439 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1440 {} /* terminator */
1441};
1442
Matthew Ranostaya7662642008-02-21 07:51:14 +01001443static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001444 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1445 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1446 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001447 0x01452050,
1448};
1449
1450static unsigned int dell_m6_pin_configs[13] = {
1451 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001452 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001453 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1454 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001455};
1456
1457static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001458 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1459 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001460};
1461
1462static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1463 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001464 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001465};
1466
1467static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1468 /* SigmaTel reference board */
1469 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001470 "DFI LanParty", STAC_92HD73XX_REF),
1471 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1472 "unknown Dell", STAC_DELL_M6),
1473 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1474 "unknown Dell", STAC_DELL_M6),
1475 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1476 "unknown Dell", STAC_DELL_M6),
1477 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1478 "unknown Dell", STAC_DELL_M6),
1479 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1480 "unknown Dell", STAC_DELL_M6),
1481 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1482 "unknown Dell", STAC_DELL_M6),
1483 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1484 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001485 {} /* terminator */
1486};
1487
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001488static unsigned int ref92hd83xxx_pin_configs[14] = {
1489 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1490 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1491 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1492 0x01451160, 0x98560170,
1493};
1494
1495static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1496 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1497};
1498
1499static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1500 [STAC_92HD83XXX_REF] = "ref",
1501};
1502
1503static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1504 /* SigmaTel reference board */
1505 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1506 "DFI LanParty", STAC_92HD71BXX_REF),
1507};
1508
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001509static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001510 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001511 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001512 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001513};
1514
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001515static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001516 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001517 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001518 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001519};
1520
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001521static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001522 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1523 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001524 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001525};
1526
Matthew Ranostaye035b842007-11-06 11:53:55 +01001527static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1528 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001529 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1530 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001531 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001532};
1533
1534static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1535 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001536 [STAC_DELL_M4_1] = "dell-m4-1",
1537 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001538 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001539};
1540
1541static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1542 /* SigmaTel reference board */
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1544 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001545 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1546 "unknown Dell", STAC_DELL_M4_1),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1548 "unknown Dell", STAC_DELL_M4_1),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1550 "unknown Dell", STAC_DELL_M4_1),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1552 "unknown Dell", STAC_DELL_M4_1),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1554 "unknown Dell", STAC_DELL_M4_1),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1556 "unknown Dell", STAC_DELL_M4_1),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1558 "unknown Dell", STAC_DELL_M4_1),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1560 "unknown Dell", STAC_DELL_M4_2),
1561 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1562 "unknown Dell", STAC_DELL_M4_2),
1563 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1564 "unknown Dell", STAC_DELL_M4_2),
1565 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1566 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001567 {} /* terminator */
1568};
1569
Matt Porter403d1942005-11-29 15:00:51 +01001570static unsigned int ref922x_pin_configs[10] = {
1571 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1572 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001573 0x40000100, 0x40000100,
1574};
1575
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001576/*
1577 STAC 922X pin configs for
1578 102801A7
1579 102801AB
1580 102801A9
1581 102801D1
1582 102801D2
1583*/
1584static unsigned int dell_922x_d81_pin_configs[10] = {
1585 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1586 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1587 0x01813122, 0x400001f2,
1588};
1589
1590/*
1591 STAC 922X pin configs for
1592 102801AC
1593 102801D0
1594*/
1595static unsigned int dell_922x_d82_pin_configs[10] = {
1596 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1597 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1598 0x01813122, 0x400001f1,
1599};
1600
1601/*
1602 STAC 922X pin configs for
1603 102801BF
1604*/
1605static unsigned int dell_922x_m81_pin_configs[10] = {
1606 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1607 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1608 0x40C003f1, 0x405003f0,
1609};
1610
1611/*
1612 STAC 9221 A1 pin configs for
1613 102801D7 (Dell XPS M1210)
1614*/
1615static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001616 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1617 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001618 0x508003f3, 0x405003f4,
1619};
1620
Matt Porter403d1942005-11-29 15:00:51 +01001621static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001622 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001623 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1624 0x02a19120, 0x40000100,
1625};
1626
1627static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001628 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1629 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001630 0x02a19320, 0x40000100,
1631};
1632
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001633static unsigned int intel_mac_v1_pin_configs[10] = {
1634 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1635 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001636 0x400000fc, 0x400000fb,
1637};
1638
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001639static unsigned int intel_mac_v2_pin_configs[10] = {
1640 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1641 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001642 0x400000fc, 0x400000fb,
1643};
1644
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001645static unsigned int intel_mac_v3_pin_configs[10] = {
1646 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1647 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1648 0x400000fc, 0x400000fb,
1649};
1650
1651static unsigned int intel_mac_v4_pin_configs[10] = {
1652 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1653 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1654 0x400000fc, 0x400000fb,
1655};
1656
1657static unsigned int intel_mac_v5_pin_configs[10] = {
1658 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1659 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1660 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001661};
1662
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001663static unsigned int ecs202_pin_configs[10] = {
1664 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1665 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1666 0x9037012e, 0x40e000f2,
1667};
Takashi Iwai76c08822007-06-19 12:17:42 +02001668
Takashi Iwai19039bd2006-06-28 15:52:16 +02001669static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001670 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001671 [STAC_D945GTP3] = d945gtp3_pin_configs,
1672 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001673 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1674 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1675 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1676 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1677 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001678 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001679 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001680 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1681 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1682 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1683 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1684 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1685 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001686 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001687 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1688 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1689 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1690 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001691};
1692
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001693static const char *stac922x_models[STAC_922X_MODELS] = {
1694 [STAC_D945_REF] = "ref",
1695 [STAC_D945GTP5] = "5stack",
1696 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001697 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1698 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1699 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1700 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1701 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001702 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001703 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001704 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001705 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001706 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1707 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001708 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001709 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001710 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001711 [STAC_922X_DELL_D81] = "dell-d81",
1712 [STAC_922X_DELL_D82] = "dell-d82",
1713 [STAC_922X_DELL_M81] = "dell-m81",
1714 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001715};
1716
1717static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1718 /* SigmaTel reference board */
1719 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1720 "DFI LanParty", STAC_D945_REF),
1721 /* Intel 945G based systems */
1722 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1723 "Intel D945G", STAC_D945GTP3),
1724 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1725 "Intel D945G", STAC_D945GTP3),
1726 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1727 "Intel D945G", STAC_D945GTP3),
1728 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1729 "Intel D945G", STAC_D945GTP3),
1730 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1731 "Intel D945G", STAC_D945GTP3),
1732 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1733 "Intel D945G", STAC_D945GTP3),
1734 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1735 "Intel D945G", STAC_D945GTP3),
1736 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1737 "Intel D945G", STAC_D945GTP3),
1738 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1739 "Intel D945G", STAC_D945GTP3),
1740 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1741 "Intel D945G", STAC_D945GTP3),
1742 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1743 "Intel D945G", STAC_D945GTP3),
1744 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1745 "Intel D945G", STAC_D945GTP3),
1746 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1747 "Intel D945G", STAC_D945GTP3),
1748 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1749 "Intel D945G", STAC_D945GTP3),
1750 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1751 "Intel D945G", STAC_D945GTP3),
1752 /* Intel D945G 5-stack systems */
1753 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1754 "Intel D945G", STAC_D945GTP5),
1755 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1756 "Intel D945G", STAC_D945GTP5),
1757 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1758 "Intel D945G", STAC_D945GTP5),
1759 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1760 "Intel D945G", STAC_D945GTP5),
1761 /* Intel 945P based systems */
1762 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1763 "Intel D945P", STAC_D945GTP3),
1764 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1765 "Intel D945P", STAC_D945GTP3),
1766 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1767 "Intel D945P", STAC_D945GTP3),
1768 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1769 "Intel D945P", STAC_D945GTP3),
1770 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1771 "Intel D945P", STAC_D945GTP3),
1772 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1773 "Intel D945P", STAC_D945GTP5),
1774 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001775 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001776 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001777 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001778 /* Dell systems */
1779 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1780 "unknown Dell", STAC_922X_DELL_D81),
1781 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1782 "unknown Dell", STAC_922X_DELL_D81),
1783 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1784 "unknown Dell", STAC_922X_DELL_D81),
1785 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1786 "unknown Dell", STAC_922X_DELL_D82),
1787 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1788 "unknown Dell", STAC_922X_DELL_M81),
1789 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1790 "unknown Dell", STAC_922X_DELL_D82),
1791 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1792 "unknown Dell", STAC_922X_DELL_D81),
1793 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1794 "unknown Dell", STAC_922X_DELL_D81),
1795 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1796 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001797 /* ECS/PC Chips boards */
1798 SND_PCI_QUIRK(0x1019, 0x2144,
1799 "ECS/PC chips", STAC_ECS_202),
1800 SND_PCI_QUIRK(0x1019, 0x2608,
1801 "ECS/PC chips", STAC_ECS_202),
1802 SND_PCI_QUIRK(0x1019, 0x2633,
1803 "ECS/PC chips P17G/1333", STAC_ECS_202),
1804 SND_PCI_QUIRK(0x1019, 0x2811,
1805 "ECS/PC chips", STAC_ECS_202),
1806 SND_PCI_QUIRK(0x1019, 0x2812,
1807 "ECS/PC chips", STAC_ECS_202),
1808 SND_PCI_QUIRK(0x1019, 0x2813,
1809 "ECS/PC chips", STAC_ECS_202),
1810 SND_PCI_QUIRK(0x1019, 0x2814,
1811 "ECS/PC chips", STAC_ECS_202),
1812 SND_PCI_QUIRK(0x1019, 0x2815,
1813 "ECS/PC chips", STAC_ECS_202),
1814 SND_PCI_QUIRK(0x1019, 0x2816,
1815 "ECS/PC chips", STAC_ECS_202),
1816 SND_PCI_QUIRK(0x1019, 0x2817,
1817 "ECS/PC chips", STAC_ECS_202),
1818 SND_PCI_QUIRK(0x1019, 0x2818,
1819 "ECS/PC chips", STAC_ECS_202),
1820 SND_PCI_QUIRK(0x1019, 0x2819,
1821 "ECS/PC chips", STAC_ECS_202),
1822 SND_PCI_QUIRK(0x1019, 0x2820,
1823 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001824 {} /* terminator */
1825};
1826
Matt Porter3cc08dc2006-01-23 15:27:49 +01001827static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001828 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1829 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1830 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1831 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001832};
1833
Tobin Davis93ed1502006-09-01 21:03:12 +02001834static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001835 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1836 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1837 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1838 0x40000100, 0x40000100
1839};
1840
Tobin Davis93ed1502006-09-01 21:03:12 +02001841static unsigned int d965_5st_pin_configs[14] = {
1842 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1843 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1844 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1845 0x40000100, 0x40000100
1846};
1847
Tobin Davis4ff076e2007-08-07 11:48:12 +02001848static unsigned int dell_3st_pin_configs[14] = {
1849 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1850 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001851 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001852 0x40c003fc, 0x40000100
1853};
1854
Tobin Davis93ed1502006-09-01 21:03:12 +02001855static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001856 [STAC_D965_REF] = ref927x_pin_configs,
1857 [STAC_D965_3ST] = d965_3st_pin_configs,
1858 [STAC_D965_5ST] = d965_5st_pin_configs,
1859 [STAC_DELL_3ST] = dell_3st_pin_configs,
1860 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001861};
1862
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001863static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001864 [STAC_D965_REF] = "ref",
1865 [STAC_D965_3ST] = "3stack",
1866 [STAC_D965_5ST] = "5stack",
1867 [STAC_DELL_3ST] = "dell-3stack",
1868 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001869};
1870
1871static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1872 /* SigmaTel reference board */
1873 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1874 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001875 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001876 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1877 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001878 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001879 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1880 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1881 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1882 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1883 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1884 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1885 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1886 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1887 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1888 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1889 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1890 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1891 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1892 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1893 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1894 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001895 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001896 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001897 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001898 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1899 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001900 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001901 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1902 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001903 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02001904 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001905 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1906 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1907 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1908 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001909 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001910 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1911 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1912 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1913 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1914 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1915 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1916 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1917 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1918 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001919 {} /* terminator */
1920};
1921
Matt Porterf3302a52006-07-31 12:49:34 +02001922static unsigned int ref9205_pin_configs[12] = {
1923 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001924 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001925 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001926};
1927
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001928/*
1929 STAC 9205 pin configs for
1930 102801F1
1931 102801F2
1932 102801FC
1933 102801FD
1934 10280204
1935 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001936 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001937*/
1938static unsigned int dell_9205_m42_pin_configs[12] = {
1939 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1940 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1941 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1942};
1943
1944/*
1945 STAC 9205 pin configs for
1946 102801F9
1947 102801FA
1948 102801FE
1949 102801FF (Dell Precision M4300)
1950 10280206
1951 10280200
1952 10280201
1953*/
1954static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001955 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1956 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1957 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1958};
1959
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001960static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001961 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1962 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1963 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1964};
1965
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001966static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001967 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001968 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1969 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1970 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001971};
1972
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001973static const char *stac9205_models[STAC_9205_MODELS] = {
1974 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001975 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001976 [STAC_9205_DELL_M43] = "dell-m43",
1977 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001978};
1979
1980static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1981 /* SigmaTel reference board */
1982 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1983 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001984 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1985 "unknown Dell", STAC_9205_DELL_M42),
1986 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1987 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001988 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001989 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001990 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1991 "Dell Precision", STAC_9205_DELL_M43),
1992 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1993 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001994 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1995 "unknown Dell", STAC_9205_DELL_M42),
1996 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1997 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001998 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1999 "Dell Precision", STAC_9205_DELL_M43),
2000 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002001 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002002 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2003 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002004 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2005 "Dell Precision", STAC_9205_DELL_M43),
2006 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2007 "Dell Precision", STAC_9205_DELL_M43),
2008 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2009 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002010 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2011 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002012 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2013 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002014 {} /* terminator */
2015};
2016
Richard Fish11b44bb2006-08-23 18:31:34 +02002017static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2018{
2019 int i;
2020 struct sigmatel_spec *spec = codec->spec;
2021
2022 if (! spec->bios_pin_configs) {
2023 spec->bios_pin_configs = kcalloc(spec->num_pins,
2024 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2025 if (! spec->bios_pin_configs)
2026 return -ENOMEM;
2027 }
2028
2029 for (i = 0; i < spec->num_pins; i++) {
2030 hda_nid_t nid = spec->pin_nids[i];
2031 unsigned int pin_cfg;
2032
2033 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2034 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2035 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2036 nid, pin_cfg);
2037 spec->bios_pin_configs[i] = pin_cfg;
2038 }
2039
2040 return 0;
2041}
2042
Matthew Ranostay87d48362007-07-17 11:52:24 +02002043static void stac92xx_set_config_reg(struct hda_codec *codec,
2044 hda_nid_t pin_nid, unsigned int pin_config)
2045{
2046 int i;
2047 snd_hda_codec_write(codec, pin_nid, 0,
2048 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2049 pin_config & 0x000000ff);
2050 snd_hda_codec_write(codec, pin_nid, 0,
2051 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2052 (pin_config & 0x0000ff00) >> 8);
2053 snd_hda_codec_write(codec, pin_nid, 0,
2054 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2055 (pin_config & 0x00ff0000) >> 16);
2056 snd_hda_codec_write(codec, pin_nid, 0,
2057 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2058 pin_config >> 24);
2059 i = snd_hda_codec_read(codec, pin_nid, 0,
2060 AC_VERB_GET_CONFIG_DEFAULT,
2061 0x00);
2062 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2063 pin_nid, i);
2064}
2065
Matt2f2f4252005-04-13 14:45:30 +02002066static void stac92xx_set_config_regs(struct hda_codec *codec)
2067{
2068 int i;
2069 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002070
Matthew Ranostay87d48362007-07-17 11:52:24 +02002071 if (!spec->pin_configs)
2072 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002073
Matthew Ranostay87d48362007-07-17 11:52:24 +02002074 for (i = 0; i < spec->num_pins; i++)
2075 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2076 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002077}
Matt2f2f4252005-04-13 14:45:30 +02002078
Matt2f2f4252005-04-13 14:45:30 +02002079/*
2080 * Analog playback callbacks
2081 */
2082static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2083 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002084 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002085{
2086 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002087 if (spec->stream_delay)
2088 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002089 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2090 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002091}
2092
2093static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2094 struct hda_codec *codec,
2095 unsigned int stream_tag,
2096 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002097 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002098{
2099 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002100 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002101}
2102
2103static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2104 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002105 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002106{
2107 struct sigmatel_spec *spec = codec->spec;
2108 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2109}
2110
2111/*
Mattdabbed62005-06-14 10:19:34 +02002112 * Digital playback callbacks
2113 */
2114static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2115 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002116 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002117{
2118 struct sigmatel_spec *spec = codec->spec;
2119 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2120}
2121
2122static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2123 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002124 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002125{
2126 struct sigmatel_spec *spec = codec->spec;
2127 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2128}
2129
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002130static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2131 struct hda_codec *codec,
2132 unsigned int stream_tag,
2133 unsigned int format,
2134 struct snd_pcm_substream *substream)
2135{
2136 struct sigmatel_spec *spec = codec->spec;
2137 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2138 stream_tag, format, substream);
2139}
2140
Mattdabbed62005-06-14 10:19:34 +02002141
2142/*
Matt2f2f4252005-04-13 14:45:30 +02002143 * Analog capture callbacks
2144 */
2145static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2146 struct hda_codec *codec,
2147 unsigned int stream_tag,
2148 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002149 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002150{
2151 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002152 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002153
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002154 if (spec->powerdown_adcs) {
2155 msleep(40);
2156 snd_hda_codec_write_cache(codec, nid, 0,
2157 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2158 }
2159 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002160 return 0;
2161}
2162
2163static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2164 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002165 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002166{
2167 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002168 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002169
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002170 snd_hda_codec_cleanup_stream(codec, nid);
2171 if (spec->powerdown_adcs)
2172 snd_hda_codec_write_cache(codec, nid, 0,
2173 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002174 return 0;
2175}
2176
Mattdabbed62005-06-14 10:19:34 +02002177static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2178 .substreams = 1,
2179 .channels_min = 2,
2180 .channels_max = 2,
2181 /* NID is set in stac92xx_build_pcms */
2182 .ops = {
2183 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002184 .close = stac92xx_dig_playback_pcm_close,
2185 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002186 },
2187};
2188
2189static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2190 .substreams = 1,
2191 .channels_min = 2,
2192 .channels_max = 2,
2193 /* NID is set in stac92xx_build_pcms */
2194};
2195
Matt2f2f4252005-04-13 14:45:30 +02002196static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2197 .substreams = 1,
2198 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002199 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002200 .nid = 0x02, /* NID to query formats and rates */
2201 .ops = {
2202 .open = stac92xx_playback_pcm_open,
2203 .prepare = stac92xx_playback_pcm_prepare,
2204 .cleanup = stac92xx_playback_pcm_cleanup
2205 },
2206};
2207
Matt Porter3cc08dc2006-01-23 15:27:49 +01002208static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2209 .substreams = 1,
2210 .channels_min = 2,
2211 .channels_max = 2,
2212 .nid = 0x06, /* NID to query formats and rates */
2213 .ops = {
2214 .open = stac92xx_playback_pcm_open,
2215 .prepare = stac92xx_playback_pcm_prepare,
2216 .cleanup = stac92xx_playback_pcm_cleanup
2217 },
2218};
2219
Matt2f2f4252005-04-13 14:45:30 +02002220static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002221 .channels_min = 2,
2222 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002223 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002224 .ops = {
2225 .prepare = stac92xx_capture_pcm_prepare,
2226 .cleanup = stac92xx_capture_pcm_cleanup
2227 },
2228};
2229
2230static int stac92xx_build_pcms(struct hda_codec *codec)
2231{
2232 struct sigmatel_spec *spec = codec->spec;
2233 struct hda_pcm *info = spec->pcm_rec;
2234
2235 codec->num_pcms = 1;
2236 codec->pcm_info = info;
2237
Mattc7d4b2f2005-06-27 14:59:41 +02002238 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002239 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002240 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002241 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002242 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002243
2244 if (spec->alt_switch) {
2245 codec->num_pcms++;
2246 info++;
2247 info->name = "STAC92xx Analog Alt";
2248 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2249 }
Matt2f2f4252005-04-13 14:45:30 +02002250
Mattdabbed62005-06-14 10:19:34 +02002251 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2252 codec->num_pcms++;
2253 info++;
2254 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002255 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002256 if (spec->multiout.dig_out_nid) {
2257 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2258 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2259 }
2260 if (spec->dig_in_nid) {
2261 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2262 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2263 }
2264 }
2265
Matt2f2f4252005-04-13 14:45:30 +02002266 return 0;
2267}
2268
Takashi Iwaic960a032006-03-23 17:06:28 +01002269static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2270{
2271 unsigned int pincap = snd_hda_param_read(codec, nid,
2272 AC_PAR_PIN_CAP);
2273 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2274 if (pincap & AC_PINCAP_VREF_100)
2275 return AC_PINCTL_VREF_100;
2276 if (pincap & AC_PINCAP_VREF_80)
2277 return AC_PINCTL_VREF_80;
2278 if (pincap & AC_PINCAP_VREF_50)
2279 return AC_PINCTL_VREF_50;
2280 if (pincap & AC_PINCAP_VREF_GRD)
2281 return AC_PINCTL_VREF_GRD;
2282 return 0;
2283}
2284
Matt Porter403d1942005-11-29 15:00:51 +01002285static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2286
2287{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002288 snd_hda_codec_write_cache(codec, nid, 0,
2289 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002290}
2291
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002292#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2293
2294static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2295 struct snd_ctl_elem_value *ucontrol)
2296{
2297 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2298 struct sigmatel_spec *spec = codec->spec;
2299
2300 ucontrol->value.integer.value[0] = spec->hp_switch;
2301 return 0;
2302}
2303
2304static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2305 struct snd_ctl_elem_value *ucontrol)
2306{
2307 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2308 struct sigmatel_spec *spec = codec->spec;
2309
2310 spec->hp_switch = ucontrol->value.integer.value[0];
2311
2312 /* check to be sure that the ports are upto date with
2313 * switch changes
2314 */
2315 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2316
2317 return 1;
2318}
2319
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002320#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002321
2322static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2323{
2324 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2325 struct sigmatel_spec *spec = codec->spec;
2326 int io_idx = kcontrol-> private_value & 0xff;
2327
2328 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2329 return 0;
2330}
2331
2332static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2333{
2334 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2335 struct sigmatel_spec *spec = codec->spec;
2336 hda_nid_t nid = kcontrol->private_value >> 8;
2337 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002338 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002339
2340 spec->io_switch[io_idx] = val;
2341
2342 if (val)
2343 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002344 else {
2345 unsigned int pinctl = AC_PINCTL_IN_EN;
2346 if (io_idx) /* set VREF for mic */
2347 pinctl |= stac92xx_get_vref(codec, nid);
2348 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2349 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002350
2351 /* check the auto-mute again: we need to mute/unmute the speaker
2352 * appropriately according to the pin direction
2353 */
2354 if (spec->hp_detect)
2355 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2356
Matt Porter403d1942005-11-29 15:00:51 +01002357 return 1;
2358}
2359
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002360#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2361
2362static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2363 struct snd_ctl_elem_value *ucontrol)
2364{
2365 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2366 struct sigmatel_spec *spec = codec->spec;
2367
2368 ucontrol->value.integer.value[0] = spec->clfe_swap;
2369 return 0;
2370}
2371
2372static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2373 struct snd_ctl_elem_value *ucontrol)
2374{
2375 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2376 struct sigmatel_spec *spec = codec->spec;
2377 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002378 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002379
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002380 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002381 return 0;
2382
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002383 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002384
2385 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2386 spec->clfe_swap ? 0x4 : 0x0);
2387
2388 return 1;
2389}
2390
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002391#define STAC_CODEC_HP_SWITCH(xname) \
2392 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2393 .name = xname, \
2394 .index = 0, \
2395 .info = stac92xx_hp_switch_info, \
2396 .get = stac92xx_hp_switch_get, \
2397 .put = stac92xx_hp_switch_put, \
2398 }
2399
Matt Porter403d1942005-11-29 15:00:51 +01002400#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2401 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2402 .name = xname, \
2403 .index = 0, \
2404 .info = stac92xx_io_switch_info, \
2405 .get = stac92xx_io_switch_get, \
2406 .put = stac92xx_io_switch_put, \
2407 .private_value = xpval, \
2408 }
2409
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002410#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2411 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2412 .name = xname, \
2413 .index = 0, \
2414 .info = stac92xx_clfe_switch_info, \
2415 .get = stac92xx_clfe_switch_get, \
2416 .put = stac92xx_clfe_switch_put, \
2417 .private_value = xpval, \
2418 }
Matt Porter403d1942005-11-29 15:00:51 +01002419
Mattc7d4b2f2005-06-27 14:59:41 +02002420enum {
2421 STAC_CTL_WIDGET_VOL,
2422 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002423 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002424 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002425 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002426 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002427};
2428
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002429static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002430 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2431 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002432 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002433 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002434 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002435 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002436};
2437
2438/* add dynamic controls */
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002439static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
2440 int idx, const char *name, unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002441{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002442 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002443
2444 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2445 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2446
2447 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2448 if (! knew)
2449 return -ENOMEM;
2450 if (spec->kctl_alloc) {
2451 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2452 kfree(spec->kctl_alloc);
2453 }
2454 spec->kctl_alloc = knew;
2455 spec->num_kctl_alloc = num;
2456 }
2457
2458 knew = &spec->kctl_alloc[spec->num_kctl_used];
2459 *knew = stac92xx_control_templates[type];
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002460 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002461 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002462 if (! knew->name)
2463 return -ENOMEM;
2464 knew->private_value = val;
2465 spec->num_kctl_used++;
2466 return 0;
2467}
2468
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002469
2470/* add dynamic controls */
2471static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2472 const char *name, unsigned long val)
2473{
2474 return stac92xx_add_control_idx(spec, type, 0, name, val);
2475}
2476
Matt Porter403d1942005-11-29 15:00:51 +01002477/* flag inputs as additional dynamic lineouts */
2478static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2479{
2480 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002481 unsigned int wcaps, wtype;
2482 int i, num_dacs = 0;
2483
2484 /* use the wcaps cache to count all DACs available for line-outs */
2485 for (i = 0; i < codec->num_nodes; i++) {
2486 wcaps = codec->wcaps[i];
2487 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002488
Steve Longerbeam7b043892007-05-03 20:50:03 +02002489 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2490 num_dacs++;
2491 }
Matt Porter403d1942005-11-29 15:00:51 +01002492
Steve Longerbeam7b043892007-05-03 20:50:03 +02002493 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2494
Matt Porter403d1942005-11-29 15:00:51 +01002495 switch (cfg->line_outs) {
2496 case 3:
2497 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002498 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002499 cfg->line_out_pins[cfg->line_outs] =
2500 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002501 spec->line_switch = 1;
2502 cfg->line_outs++;
2503 }
2504 break;
2505 case 2:
2506 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002507 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002508 cfg->line_out_pins[cfg->line_outs] =
2509 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002510 spec->line_switch = 1;
2511 cfg->line_outs++;
2512 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002513 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002514 cfg->line_out_pins[cfg->line_outs] =
2515 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002516 spec->mic_switch = 1;
2517 cfg->line_outs++;
2518 }
2519 break;
2520 case 1:
2521 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002522 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002523 cfg->line_out_pins[cfg->line_outs] =
2524 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002525 spec->line_switch = 1;
2526 cfg->line_outs++;
2527 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002528 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002529 cfg->line_out_pins[cfg->line_outs] =
2530 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002531 spec->mic_switch = 1;
2532 cfg->line_outs++;
2533 }
2534 break;
2535 }
2536
2537 return 0;
2538}
2539
Steve Longerbeam7b043892007-05-03 20:50:03 +02002540
2541static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2542{
2543 int i;
2544
2545 for (i = 0; i < spec->multiout.num_dacs; i++) {
2546 if (spec->multiout.dac_nids[i] == nid)
2547 return 1;
2548 }
2549
2550 return 0;
2551}
2552
Matt Porter3cc08dc2006-01-23 15:27:49 +01002553/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002554 * Fill in the dac_nids table from the parsed pin configuration
2555 * This function only works when every pin in line_out_pins[]
2556 * contains atleast one DAC in its connection list. Some 92xx
2557 * codecs are not connected directly to a DAC, such as the 9200
2558 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002559 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002560static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002561 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002562{
2563 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002564 int i, j, conn_len = 0;
2565 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2566 unsigned int wcaps, wtype;
2567
Mattc7d4b2f2005-06-27 14:59:41 +02002568 for (i = 0; i < cfg->line_outs; i++) {
2569 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002570 conn_len = snd_hda_get_connections(codec, nid, conn,
2571 HDA_MAX_CONNECTIONS);
2572 for (j = 0; j < conn_len; j++) {
2573 wcaps = snd_hda_param_read(codec, conn[j],
2574 AC_PAR_AUDIO_WIDGET_CAP);
2575 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002576 if (wtype != AC_WID_AUD_OUT ||
2577 (wcaps & AC_WCAP_DIGITAL))
2578 continue;
2579 /* conn[j] is a DAC routed to this line-out */
2580 if (!is_in_dac_nids(spec, conn[j]))
2581 break;
2582 }
2583
2584 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002585 if (spec->multiout.num_dacs > 0) {
2586 /* we have already working output pins,
2587 * so let's drop the broken ones again
2588 */
2589 cfg->line_outs = spec->multiout.num_dacs;
2590 break;
2591 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002592 /* error out, no available DAC found */
2593 snd_printk(KERN_ERR
2594 "%s: No available DAC for pin 0x%x\n",
2595 __func__, nid);
2596 return -ENODEV;
2597 }
2598
2599 spec->multiout.dac_nids[i] = conn[j];
2600 spec->multiout.num_dacs++;
2601 if (conn_len > 1) {
2602 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002603 snd_hda_codec_write_cache(codec, nid, 0,
2604 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002605
2606 }
Mattc7d4b2f2005-06-27 14:59:41 +02002607 }
2608
Steve Longerbeam7b043892007-05-03 20:50:03 +02002609 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2610 spec->multiout.num_dacs,
2611 spec->multiout.dac_nids[0],
2612 spec->multiout.dac_nids[1],
2613 spec->multiout.dac_nids[2],
2614 spec->multiout.dac_nids[3],
2615 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002616 return 0;
2617}
2618
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002619/* create volume control/switch for the given prefx type */
2620static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2621{
2622 char name[32];
2623 int err;
2624
2625 sprintf(name, "%s Playback Volume", pfx);
2626 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2627 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2628 if (err < 0)
2629 return err;
2630 sprintf(name, "%s Playback Switch", pfx);
2631 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2632 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2633 if (err < 0)
2634 return err;
2635 return 0;
2636}
2637
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002638static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2639{
2640 if (!spec->multiout.hp_nid)
2641 spec->multiout.hp_nid = nid;
2642 else if (spec->multiout.num_dacs > 4) {
2643 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2644 return 1;
2645 } else {
2646 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2647 spec->multiout.num_dacs++;
2648 }
2649 return 0;
2650}
2651
2652static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2653{
2654 if (is_in_dac_nids(spec, nid))
2655 return 1;
2656 if (spec->multiout.hp_nid == nid)
2657 return 1;
2658 return 0;
2659}
2660
Mattc7d4b2f2005-06-27 14:59:41 +02002661/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002662static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002663 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002664{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002665 static const char *chname[4] = {
2666 "Front", "Surround", NULL /*CLFE*/, "Side"
2667 };
Mattc7d4b2f2005-06-27 14:59:41 +02002668 hda_nid_t nid;
2669 int i, err;
2670
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002671 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002672 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002673
2674
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002675 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002676 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002677 continue;
2678
2679 nid = spec->multiout.dac_nids[i];
2680
2681 if (i == 2) {
2682 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002683 err = create_controls(spec, "Center", nid, 1);
2684 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002685 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002686 err = create_controls(spec, "LFE", nid, 2);
2687 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002688 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002689
2690 wid_caps = get_wcaps(codec, nid);
2691
2692 if (wid_caps & AC_WCAP_LR_SWAP) {
2693 err = stac92xx_add_control(spec,
2694 STAC_CTL_WIDGET_CLFE_SWITCH,
2695 "Swap Center/LFE Playback Switch", nid);
2696
2697 if (err < 0)
2698 return err;
2699 }
2700
Mattc7d4b2f2005-06-27 14:59:41 +02002701 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002702 err = create_controls(spec, chname[i], nid, 3);
2703 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002704 return err;
2705 }
2706 }
2707
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002708 if (cfg->hp_outs > 1) {
2709 err = stac92xx_add_control(spec,
2710 STAC_CTL_WIDGET_HP_SWITCH,
2711 "Headphone as Line Out Switch", 0);
2712 if (err < 0)
2713 return err;
2714 }
2715
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002716 if (spec->line_switch) {
2717 nid = cfg->input_pins[AUTO_PIN_LINE];
2718 pincap = snd_hda_param_read(codec, nid,
2719 AC_PAR_PIN_CAP);
2720 if (pincap & AC_PINCAP_OUT) {
2721 err = stac92xx_add_control(spec,
2722 STAC_CTL_WIDGET_IO_SWITCH,
2723 "Line In as Output Switch", nid << 8);
2724 if (err < 0)
2725 return err;
2726 }
2727 }
Matt Porter403d1942005-11-29 15:00:51 +01002728
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002729 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002730 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002731 unsigned int mic_pin = AUTO_PIN_MIC;
2732again:
2733 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002734 def_conf = snd_hda_codec_read(codec, nid, 0,
2735 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002736 /* some laptops have an internal analog microphone
2737 * which can't be used as a output */
2738 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2739 pincap = snd_hda_param_read(codec, nid,
2740 AC_PAR_PIN_CAP);
2741 if (pincap & AC_PINCAP_OUT) {
2742 err = stac92xx_add_control(spec,
2743 STAC_CTL_WIDGET_IO_SWITCH,
2744 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002745 nid = snd_hda_codec_read(codec, nid, 0,
2746 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2747 if (!check_in_dac_nids(spec, nid))
2748 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002749 if (err < 0)
2750 return err;
2751 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002752 } else if (mic_pin == AUTO_PIN_MIC) {
2753 mic_pin = AUTO_PIN_FRONT_MIC;
2754 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002755 }
2756 }
Matt Porter403d1942005-11-29 15:00:51 +01002757
Mattc7d4b2f2005-06-27 14:59:41 +02002758 return 0;
2759}
2760
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002761/* add playback controls for Speaker and HP outputs */
2762static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2763 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002764{
2765 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002766 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002767 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002768
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002769 old_num_dacs = spec->multiout.num_dacs;
2770 for (i = 0; i < cfg->hp_outs; i++) {
2771 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2772 if (wid_caps & AC_WCAP_UNSOL_CAP)
2773 spec->hp_detect = 1;
2774 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2775 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2776 if (check_in_dac_nids(spec, nid))
2777 nid = 0;
2778 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002779 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002780 add_spec_dacs(spec, nid);
2781 }
2782 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002783 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002784 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2785 if (check_in_dac_nids(spec, nid))
2786 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002787 if (! nid)
2788 continue;
2789 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002790 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002791 for (i = 0; i < cfg->line_outs; i++) {
2792 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2793 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2794 if (check_in_dac_nids(spec, nid))
2795 nid = 0;
2796 if (! nid)
2797 continue;
2798 add_spec_dacs(spec, nid);
2799 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002800 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2801 static const char *pfxs[] = {
2802 "Speaker", "External Speaker", "Speaker2",
2803 };
2804 err = create_controls(spec, pfxs[i - old_num_dacs],
2805 spec->multiout.dac_nids[i], 3);
2806 if (err < 0)
2807 return err;
2808 }
2809 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002810 err = create_controls(spec, "Headphone",
2811 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002812 if (err < 0)
2813 return err;
2814 }
Mattc7d4b2f2005-06-27 14:59:41 +02002815
2816 return 0;
2817}
2818
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002819/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002820static const char *stac92xx_mono_labels[4] = {
2821 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002822};
2823
2824/* create mono mux for mono out on capable codecs */
2825static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2826{
2827 struct sigmatel_spec *spec = codec->spec;
2828 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2829 int i, num_cons;
2830 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2831
2832 num_cons = snd_hda_get_connections(codec,
2833 spec->mono_nid,
2834 con_lst,
2835 HDA_MAX_NUM_INPUTS);
2836 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2837 return -EINVAL;
2838
2839 for (i = 0; i < num_cons; i++) {
2840 mono_mux->items[mono_mux->num_items].label =
2841 stac92xx_mono_labels[i];
2842 mono_mux->items[mono_mux->num_items].index = i;
2843 mono_mux->num_items++;
2844 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002845
2846 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2847 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002848}
2849
Matthew Ranostay1cd22242008-07-18 18:20:52 +02002850/* create PC beep volume controls */
2851static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
2852 hda_nid_t nid)
2853{
2854 struct sigmatel_spec *spec = codec->spec;
2855 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
2856 int err;
2857
2858 /* check for mute support for the the amp */
2859 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
2860 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2861 "PC Beep Playback Switch",
2862 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2863 if (err < 0)
2864 return err;
2865 }
2866
2867 /* check to see if there is volume support for the amp */
2868 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2869 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2870 "PC Beep Playback Volume",
2871 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2872 if (err < 0)
2873 return err;
2874 }
2875 return 0;
2876}
2877
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002878static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
2879{
2880 struct sigmatel_spec *spec = codec->spec;
2881 int wcaps, nid, i, err = 0;
2882
2883 for (i = 0; i < spec->num_muxes; i++) {
2884 nid = spec->mux_nids[i];
2885 wcaps = get_wcaps(codec, nid);
2886
2887 if (wcaps & AC_WCAP_OUT_AMP) {
2888 err = stac92xx_add_control_idx(spec,
2889 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
2890 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2891 if (err < 0)
2892 return err;
2893 }
2894 }
2895 return 0;
2896};
2897
Matthew Ranostayd9737752008-09-07 12:03:41 +02002898static const char *stac92xx_spdif_labels[3] = {
2899 "Digital Playback", "Analog Mux 1", "Analog Mux 2"
2900};
2901
2902static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
2903{
2904 struct sigmatel_spec *spec = codec->spec;
2905 struct hda_input_mux *spdif_mux = &spec->private_smux;
2906 int i, num_cons;
2907 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_spdif_labels)];
2908
2909 num_cons = snd_hda_get_connections(codec,
2910 spec->smux_nids[0],
2911 con_lst,
2912 HDA_MAX_NUM_INPUTS);
2913 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_spdif_labels))
2914 return -EINVAL;
2915
2916 for (i = 0; i < num_cons; i++) {
2917 spdif_mux->items[spdif_mux->num_items].label =
2918 stac92xx_spdif_labels[i];
2919 spdif_mux->items[spdif_mux->num_items].index = i;
2920 spdif_mux->num_items++;
2921 }
2922
2923 return 0;
2924}
2925
Matt Porter8b657272006-10-26 17:12:59 +02002926/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002927static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002928 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2929 "Digital Mic 3", "Digital Mic 4"
2930};
2931
2932/* create playback/capture controls for input pins on dmic capable codecs */
2933static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2934 const struct auto_pin_cfg *cfg)
2935{
2936 struct sigmatel_spec *spec = codec->spec;
2937 struct hda_input_mux *dimux = &spec->private_dimux;
2938 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002939 int err, i, j;
2940 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002941
2942 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2943 dimux->items[dimux->num_items].index = 0;
2944 dimux->num_items++;
2945
2946 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002947 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002948 int index;
2949 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002950 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002951 unsigned int def_conf;
2952
2953 def_conf = snd_hda_codec_read(codec,
2954 spec->dmic_nids[i],
2955 0,
2956 AC_VERB_GET_CONFIG_DEFAULT,
2957 0);
2958 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2959 continue;
2960
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002961 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002962 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002963 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002964 con_lst,
2965 HDA_MAX_NUM_INPUTS);
2966 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002967 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002968 index = j;
2969 goto found;
2970 }
2971 continue;
2972found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002973 wcaps = get_wcaps(codec, nid) &
2974 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002975
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002976 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002977 sprintf(name, "%s Capture Volume",
2978 stac92xx_dmic_labels[dimux->num_items]);
2979
2980 err = stac92xx_add_control(spec,
2981 STAC_CTL_WIDGET_VOL,
2982 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002983 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
2984 (wcaps & AC_WCAP_OUT_AMP) ?
2985 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002986 if (err < 0)
2987 return err;
2988 }
2989
Matt Porter8b657272006-10-26 17:12:59 +02002990 dimux->items[dimux->num_items].label =
2991 stac92xx_dmic_labels[dimux->num_items];
2992 dimux->items[dimux->num_items].index = index;
2993 dimux->num_items++;
2994 }
2995
2996 return 0;
2997}
2998
Mattc7d4b2f2005-06-27 14:59:41 +02002999/* create playback/capture controls for input pins */
3000static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3001{
3002 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003003 struct hda_input_mux *imux = &spec->private_imux;
3004 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3005 int i, j, k;
3006
3007 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003008 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003009
Takashi Iwai314634b2006-09-21 11:56:18 +02003010 if (!cfg->input_pins[i])
3011 continue;
3012 index = -1;
3013 for (j = 0; j < spec->num_muxes; j++) {
3014 int num_cons;
3015 num_cons = snd_hda_get_connections(codec,
3016 spec->mux_nids[j],
3017 con_lst,
3018 HDA_MAX_NUM_INPUTS);
3019 for (k = 0; k < num_cons; k++)
3020 if (con_lst[k] == cfg->input_pins[i]) {
3021 index = k;
3022 goto found;
3023 }
Mattc7d4b2f2005-06-27 14:59:41 +02003024 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003025 continue;
3026 found:
3027 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3028 imux->items[imux->num_items].index = index;
3029 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003030 }
3031
Steve Longerbeam7b043892007-05-03 20:50:03 +02003032 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003033 /*
3034 * Set the current input for the muxes.
3035 * The STAC9221 has two input muxes with identical source
3036 * NID lists. Hopefully this won't get confused.
3037 */
3038 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003039 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3040 AC_VERB_SET_CONNECT_SEL,
3041 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003042 }
3043 }
3044
Mattc7d4b2f2005-06-27 14:59:41 +02003045 return 0;
3046}
3047
Mattc7d4b2f2005-06-27 14:59:41 +02003048static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3049{
3050 struct sigmatel_spec *spec = codec->spec;
3051 int i;
3052
3053 for (i = 0; i < spec->autocfg.line_outs; i++) {
3054 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3055 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3056 }
3057}
3058
3059static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3060{
3061 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003062 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003063
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003064 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3065 hda_nid_t pin;
3066 pin = spec->autocfg.hp_pins[i];
3067 if (pin) /* connect to front */
3068 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3069 }
3070 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3071 hda_nid_t pin;
3072 pin = spec->autocfg.speaker_pins[i];
3073 if (pin) /* connect to front */
3074 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3075 }
Mattc7d4b2f2005-06-27 14:59:41 +02003076}
3077
Matt Porter3cc08dc2006-01-23 15:27:49 +01003078static 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 +02003079{
3080 struct sigmatel_spec *spec = codec->spec;
3081 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003082 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003083
Matt Porter8b657272006-10-26 17:12:59 +02003084 if ((err = snd_hda_parse_pin_def_config(codec,
3085 &spec->autocfg,
3086 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003087 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003088 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003089 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003090
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003091 /* If we have no real line-out pin and multiple hp-outs, HPs should
3092 * be set up as multi-channel outputs.
3093 */
3094 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3095 spec->autocfg.hp_outs > 1) {
3096 /* Copy hp_outs to line_outs, backup line_outs in
3097 * speaker_outs so that the following routines can handle
3098 * HP pins as primary outputs.
3099 */
3100 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3101 sizeof(spec->autocfg.line_out_pins));
3102 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3103 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3104 sizeof(spec->autocfg.hp_pins));
3105 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3106 hp_speaker_swap = 1;
3107 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003108 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003109 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3110 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003111 u32 caps = query_amp_caps(codec,
3112 spec->autocfg.mono_out_pin, dir);
3113 hda_nid_t conn_list[1];
3114
3115 /* get the mixer node and then the mono mux if it exists */
3116 if (snd_hda_get_connections(codec,
3117 spec->autocfg.mono_out_pin, conn_list, 1) &&
3118 snd_hda_get_connections(codec, conn_list[0],
3119 conn_list, 1)) {
3120
3121 int wcaps = get_wcaps(codec, conn_list[0]);
3122 int wid_type = (wcaps & AC_WCAP_TYPE)
3123 >> AC_WCAP_TYPE_SHIFT;
3124 /* LR swap check, some stac925x have a mux that
3125 * changes the DACs output path instead of the
3126 * mono-mux path.
3127 */
3128 if (wid_type == AC_WID_AUD_SEL &&
3129 !(wcaps & AC_WCAP_LR_SWAP))
3130 spec->mono_nid = conn_list[0];
3131 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003132 if (dir) {
3133 hda_nid_t nid = spec->autocfg.mono_out_pin;
3134
3135 /* most mono outs have a least a mute/unmute switch */
3136 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3137 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3138 "Mono Playback Switch",
3139 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003140 if (err < 0)
3141 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003142 /* check for volume support for the amp */
3143 if ((caps & AC_AMPCAP_NUM_STEPS)
3144 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3145 err = stac92xx_add_control(spec,
3146 STAC_CTL_WIDGET_VOL,
3147 "Mono Playback Volume",
3148 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3149 if (err < 0)
3150 return err;
3151 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003152 }
3153
3154 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3155 AC_PINCTL_OUT_EN);
3156 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003157
Matt Porter403d1942005-11-29 15:00:51 +01003158 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3159 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003160 if (spec->multiout.num_dacs == 0)
3161 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3162 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003163
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003164 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3165
3166 if (err < 0)
3167 return err;
3168
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003169 /* setup analog beep controls */
3170 if (spec->anabeep_nid > 0) {
3171 err = stac92xx_auto_create_beep_ctls(codec,
3172 spec->anabeep_nid);
3173 if (err < 0)
3174 return err;
3175 }
3176
3177 /* setup digital beep controls and input device */
3178#ifdef CONFIG_SND_HDA_INPUT_BEEP
3179 if (spec->digbeep_nid > 0) {
3180 hda_nid_t nid = spec->digbeep_nid;
3181
3182 err = stac92xx_auto_create_beep_ctls(codec, nid);
3183 if (err < 0)
3184 return err;
3185 err = snd_hda_attach_beep_device(codec, nid);
3186 if (err < 0)
3187 return err;
3188 }
3189#endif
3190
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003191 if (hp_speaker_swap == 1) {
3192 /* Restore the hp_outs and line_outs */
3193 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3194 sizeof(spec->autocfg.line_out_pins));
3195 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3196 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3197 sizeof(spec->autocfg.speaker_pins));
3198 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3199 memset(spec->autocfg.speaker_pins, 0,
3200 sizeof(spec->autocfg.speaker_pins));
3201 spec->autocfg.speaker_outs = 0;
3202 }
3203
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003204 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3205
3206 if (err < 0)
3207 return err;
3208
3209 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3210
3211 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003212 return err;
3213
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003214 if (spec->mono_nid > 0) {
3215 err = stac92xx_auto_create_mono_output_ctls(codec);
3216 if (err < 0)
3217 return err;
3218 }
3219
Matt Porter8b657272006-10-26 17:12:59 +02003220 if (spec->num_dmics > 0)
3221 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3222 &spec->autocfg)) < 0)
3223 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003224 if (spec->num_muxes > 0) {
3225 err = stac92xx_auto_create_mux_input_ctls(codec);
3226 if (err < 0)
3227 return err;
3228 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003229 if (spec->num_smuxes > 0) {
3230 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3231 if (err < 0)
3232 return err;
3233 }
Matt Porter8b657272006-10-26 17:12:59 +02003234
Mattc7d4b2f2005-06-27 14:59:41 +02003235 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003236 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003237 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003238
Takashi Iwai82bc9552006-03-21 11:24:42 +01003239 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003240 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003241 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003242 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003243
3244 if (spec->kctl_alloc)
3245 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3246
3247 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003248 if (!spec->dinput_mux)
3249 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003250 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003251 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003252
3253 return 1;
3254}
3255
Takashi Iwai82bc9552006-03-21 11:24:42 +01003256/* add playback controls for HP output */
3257static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3258 struct auto_pin_cfg *cfg)
3259{
3260 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003261 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003262 unsigned int wid_caps;
3263
3264 if (! pin)
3265 return 0;
3266
3267 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003268 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003269 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003270
3271 return 0;
3272}
3273
Richard Fish160ea0d2006-09-06 13:58:25 +02003274/* add playback controls for LFE output */
3275static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3276 struct auto_pin_cfg *cfg)
3277{
3278 struct sigmatel_spec *spec = codec->spec;
3279 int err;
3280 hda_nid_t lfe_pin = 0x0;
3281 int i;
3282
3283 /*
3284 * search speaker outs and line outs for a mono speaker pin
3285 * with an amp. If one is found, add LFE controls
3286 * for it.
3287 */
3288 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3289 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003290 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003291 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3292 if (wcaps == AC_WCAP_OUT_AMP)
3293 /* found a mono speaker with an amp, must be lfe */
3294 lfe_pin = pin;
3295 }
3296
3297 /* if speaker_outs is 0, then speakers may be in line_outs */
3298 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3299 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3300 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003301 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003302 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003303 AC_VERB_GET_CONFIG_DEFAULT,
3304 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003305 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003306 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003307 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3308 if (wcaps == AC_WCAP_OUT_AMP)
3309 /* found a mono speaker with an amp,
3310 must be lfe */
3311 lfe_pin = pin;
3312 }
3313 }
3314 }
3315
3316 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003317 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003318 if (err < 0)
3319 return err;
3320 }
3321
3322 return 0;
3323}
3324
Mattc7d4b2f2005-06-27 14:59:41 +02003325static int stac9200_parse_auto_config(struct hda_codec *codec)
3326{
3327 struct sigmatel_spec *spec = codec->spec;
3328 int err;
3329
Kailang Yangdf694da2005-12-05 19:42:22 +01003330 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003331 return err;
3332
3333 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3334 return err;
3335
Takashi Iwai82bc9552006-03-21 11:24:42 +01003336 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3337 return err;
3338
Richard Fish160ea0d2006-09-06 13:58:25 +02003339 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3340 return err;
3341
Takashi Iwai82bc9552006-03-21 11:24:42 +01003342 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003343 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003344 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003345 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003346
3347 if (spec->kctl_alloc)
3348 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3349
3350 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003351 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003352
3353 return 1;
3354}
3355
Sam Revitch62fe78e2006-05-10 15:09:17 +02003356/*
3357 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3358 * funky external mute control using GPIO pins.
3359 */
3360
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003361static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003362 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003363{
3364 unsigned int gpiostate, gpiomask, gpiodir;
3365
3366 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3367 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003368 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003369
3370 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3371 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003372 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003373
3374 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3375 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003376 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003377
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003378 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003379 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3380
3381 snd_hda_codec_write(codec, codec->afg, 0,
3382 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003383 snd_hda_codec_read(codec, codec->afg, 0,
3384 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003385
3386 msleep(1);
3387
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003388 snd_hda_codec_read(codec, codec->afg, 0,
3389 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003390}
3391
Takashi Iwai314634b2006-09-21 11:56:18 +02003392static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3393 unsigned int event)
3394{
3395 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003396 snd_hda_codec_write_cache(codec, nid, 0,
3397 AC_VERB_SET_UNSOLICITED_ENABLE,
3398 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003399}
3400
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003401static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3402{
3403 int i;
3404 for (i = 0; i < cfg->hp_outs; i++)
3405 if (cfg->hp_pins[i] == nid)
3406 return 1; /* nid is a HP-Out */
3407
3408 return 0; /* nid is not a HP-Out */
3409};
3410
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003411static void stac92xx_power_down(struct hda_codec *codec)
3412{
3413 struct sigmatel_spec *spec = codec->spec;
3414
3415 /* power down inactive DACs */
3416 hda_nid_t *dac;
3417 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003418 if (!is_in_dac_nids(spec, *dac) &&
3419 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003420 snd_hda_codec_write_cache(codec, *dac, 0,
3421 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3422}
3423
Mattc7d4b2f2005-06-27 14:59:41 +02003424static int stac92xx_init(struct hda_codec *codec)
3425{
3426 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003427 struct auto_pin_cfg *cfg = &spec->autocfg;
3428 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003429
Mattc7d4b2f2005-06-27 14:59:41 +02003430 snd_hda_sequence_write(codec, spec->init);
3431
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003432 /* power down adcs initially */
3433 if (spec->powerdown_adcs)
3434 for (i = 0; i < spec->num_adcs; i++)
3435 snd_hda_codec_write_cache(codec,
3436 spec->adc_nids[i], 0,
3437 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003438 /* set up pins */
3439 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003440 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003441 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003442 enable_pin_detect(codec, cfg->hp_pins[i],
3443 STAC_HP_EVENT);
Takashi Iwai0a07aca2007-03-13 10:40:23 +01003444 /* force to enable the first line-out; the others are set up
3445 * in unsol_event
3446 */
3447 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3448 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003449 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003450 /* fake event to set up pins */
3451 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3452 } else {
3453 stac92xx_auto_init_multi_out(codec);
3454 stac92xx_auto_init_hp_out(codec);
3455 }
3456 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003457 hda_nid_t nid = cfg->input_pins[i];
3458 if (nid) {
3459 unsigned int pinctl = AC_PINCTL_IN_EN;
3460 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3461 pinctl |= stac92xx_get_vref(codec, nid);
3462 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3463 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003464 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003465 for (i = 0; i < spec->num_dmics; i++)
3466 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3467 AC_PINCTL_IN_EN);
3468 for (i = 0; i < spec->num_pwrs; i++) {
3469 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3470 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3471 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3472 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003473 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3474 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003475 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003476 /* outputs are only ports capable of power management
3477 * any attempts on powering down a input port cause the
3478 * referenced VREF to act quirky.
3479 */
3480 if (pinctl & AC_PINCTL_IN_EN)
3481 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003482 /* skip any ports that don't have jacks since presence
3483 * detection is useless */
3484 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003485 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003486 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3487 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3488 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003489 if (spec->dac_list)
3490 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003491 if (cfg->dig_out_pin)
3492 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3493 AC_PINCTL_OUT_EN);
3494 if (cfg->dig_in_pin)
3495 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3496 AC_PINCTL_IN_EN);
3497
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003498 stac_gpio_set(codec, spec->gpio_mask,
3499 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003500
Mattc7d4b2f2005-06-27 14:59:41 +02003501 return 0;
3502}
3503
Matt2f2f4252005-04-13 14:45:30 +02003504static void stac92xx_free(struct hda_codec *codec)
3505{
Mattc7d4b2f2005-06-27 14:59:41 +02003506 struct sigmatel_spec *spec = codec->spec;
3507 int i;
3508
3509 if (! spec)
3510 return;
3511
3512 if (spec->kctl_alloc) {
3513 for (i = 0; i < spec->num_kctl_used; i++)
3514 kfree(spec->kctl_alloc[i].name);
3515 kfree(spec->kctl_alloc);
3516 }
3517
Richard Fish11b44bb2006-08-23 18:31:34 +02003518 if (spec->bios_pin_configs)
3519 kfree(spec->bios_pin_configs);
3520
Mattc7d4b2f2005-06-27 14:59:41 +02003521 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003522 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003523}
3524
Matt4e550962005-07-04 17:51:39 +02003525static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3526 unsigned int flag)
3527{
3528 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3529 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003530
Takashi Iwaif9acba42007-05-29 18:01:06 +02003531 if (pin_ctl & AC_PINCTL_IN_EN) {
3532 /*
3533 * we need to check the current set-up direction of
3534 * shared input pins since they can be switched via
3535 * "xxx as Output" mixer switch
3536 */
3537 struct sigmatel_spec *spec = codec->spec;
3538 struct auto_pin_cfg *cfg = &spec->autocfg;
3539 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3540 spec->line_switch) ||
3541 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3542 spec->mic_switch))
3543 return;
3544 }
3545
Steve Longerbeam7b043892007-05-03 20:50:03 +02003546 /* if setting pin direction bits, clear the current
3547 direction bits first */
3548 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3549 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3550
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003551 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003552 AC_VERB_SET_PIN_WIDGET_CONTROL,
3553 pin_ctl | flag);
3554}
3555
3556static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3557 unsigned int flag)
3558{
3559 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3560 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003561 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003562 AC_VERB_SET_PIN_WIDGET_CONTROL,
3563 pin_ctl & ~flag);
3564}
3565
Jiang Zhe40c1d302007-11-12 13:05:16 +01003566static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003567{
3568 if (!nid)
3569 return 0;
3570 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003571 & (1 << 31)) {
3572 unsigned int pinctl;
3573 pinctl = snd_hda_codec_read(codec, nid, 0,
3574 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3575 if (pinctl & AC_PINCTL_IN_EN)
3576 return 0; /* mic- or line-input */
3577 else
3578 return 1; /* HP-output */
3579 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003580 return 0;
3581}
3582
3583static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003584{
3585 struct sigmatel_spec *spec = codec->spec;
3586 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003587 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003588 int i, presence;
3589
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003590 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003591 if (spec->gpio_mute)
3592 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3593 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3594
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003595 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003596 if (presence)
3597 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003598 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3599 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003600 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003601 }
Matt4e550962005-07-04 17:51:39 +02003602
3603 if (presence) {
3604 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003605 if (spec->hp_switch)
3606 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003607 for (i = 0; i < cfg->line_outs; i++)
3608 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3609 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003610 for (i = 0; i < cfg->speaker_outs; i++)
3611 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3612 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003613 if (spec->eapd_mask)
3614 stac_gpio_set(codec, spec->gpio_mask,
3615 spec->gpio_dir, spec->gpio_data &
3616 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003617 } else {
3618 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003619 if (spec->hp_switch)
3620 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003621 for (i = 0; i < cfg->line_outs; i++)
3622 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3623 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003624 for (i = 0; i < cfg->speaker_outs; i++)
3625 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3626 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003627 if (spec->eapd_mask)
3628 stac_gpio_set(codec, spec->gpio_mask,
3629 spec->gpio_dir, spec->gpio_data |
3630 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003631 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003632 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3633 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003634}
3635
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003636static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3637{
3638 struct sigmatel_spec *spec = codec->spec;
3639 hda_nid_t nid = spec->pwr_nids[idx];
3640 int presence, val;
3641 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3642 & 0x000000ff;
3643 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003644
3645 /* several codecs have two power down bits */
3646 if (spec->pwr_mapping)
3647 idx = spec->pwr_mapping[idx];
3648 else
3649 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003650
3651 if (presence)
3652 val &= ~idx;
3653 else
3654 val |= idx;
3655
3656 /* power down unused output ports */
3657 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3658};
3659
Takashi Iwai314634b2006-09-21 11:56:18 +02003660static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3661{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003662 struct sigmatel_spec *spec = codec->spec;
3663 int idx = res >> 26 & 0x0f;
3664
3665 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003666 case STAC_HP_EVENT:
3667 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003668 /* fallthru */
3669 case STAC_PWR_EVENT:
3670 if (spec->num_pwrs > 0)
3671 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003672 }
3673}
3674
Takashi Iwaicb53c622007-08-10 17:21:45 +02003675#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003676static int stac92xx_resume(struct hda_codec *codec)
3677{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003678 struct sigmatel_spec *spec = codec->spec;
3679
Richard Fish11b44bb2006-08-23 18:31:34 +02003680 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003681 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003682 stac_gpio_set(codec, spec->gpio_mask,
3683 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003684 snd_hda_codec_resume_amp(codec);
3685 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003686 /* power down inactive DACs */
3687 if (spec->dac_list)
3688 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003689 /* invoke unsolicited event to reset the HP state */
3690 if (spec->hp_detect)
3691 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003692 return 0;
3693}
3694#endif
3695
Matt2f2f4252005-04-13 14:45:30 +02003696static struct hda_codec_ops stac92xx_patch_ops = {
3697 .build_controls = stac92xx_build_controls,
3698 .build_pcms = stac92xx_build_pcms,
3699 .init = stac92xx_init,
3700 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003701 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003702#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003703 .resume = stac92xx_resume,
3704#endif
Matt2f2f4252005-04-13 14:45:30 +02003705};
3706
3707static int patch_stac9200(struct hda_codec *codec)
3708{
3709 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003710 int err;
Matt2f2f4252005-04-13 14:45:30 +02003711
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003712 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003713 if (spec == NULL)
3714 return -ENOMEM;
3715
3716 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003717 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003718 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003719 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3720 stac9200_models,
3721 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003722 if (spec->board_config < 0) {
3723 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3724 err = stac92xx_save_bios_config_regs(codec);
3725 if (err < 0) {
3726 stac92xx_free(codec);
3727 return err;
3728 }
3729 spec->pin_configs = spec->bios_pin_configs;
3730 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003731 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3732 stac92xx_set_config_regs(codec);
3733 }
Matt2f2f4252005-04-13 14:45:30 +02003734
3735 spec->multiout.max_channels = 2;
3736 spec->multiout.num_dacs = 1;
3737 spec->multiout.dac_nids = stac9200_dac_nids;
3738 spec->adc_nids = stac9200_adc_nids;
3739 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003740 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003741 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003742 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003743 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003744
Tobin Davisbf277782008-02-03 20:31:47 +01003745 if (spec->board_config == STAC_9200_GATEWAY ||
3746 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003747 spec->init = stac9200_eapd_init;
3748 else
3749 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003750 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003751
Takashi Iwai117f2572008-03-18 09:53:23 +01003752 if (spec->board_config == STAC_9200_PANASONIC) {
3753 spec->gpio_mask = spec->gpio_dir = 0x09;
3754 spec->gpio_data = 0x00;
3755 }
3756
Mattc7d4b2f2005-06-27 14:59:41 +02003757 err = stac9200_parse_auto_config(codec);
3758 if (err < 0) {
3759 stac92xx_free(codec);
3760 return err;
3761 }
Matt2f2f4252005-04-13 14:45:30 +02003762
3763 codec->patch_ops = stac92xx_patch_ops;
3764
3765 return 0;
3766}
3767
Tobin Davis8e21c342007-01-08 11:04:17 +01003768static int patch_stac925x(struct hda_codec *codec)
3769{
3770 struct sigmatel_spec *spec;
3771 int err;
3772
3773 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3774 if (spec == NULL)
3775 return -ENOMEM;
3776
3777 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003778 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003779 spec->pin_nids = stac925x_pin_nids;
3780 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3781 stac925x_models,
3782 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003783 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003784 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003785 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3786 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003787 err = stac92xx_save_bios_config_regs(codec);
3788 if (err < 0) {
3789 stac92xx_free(codec);
3790 return err;
3791 }
3792 spec->pin_configs = spec->bios_pin_configs;
3793 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3794 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3795 stac92xx_set_config_regs(codec);
3796 }
3797
3798 spec->multiout.max_channels = 2;
3799 spec->multiout.num_dacs = 1;
3800 spec->multiout.dac_nids = stac925x_dac_nids;
3801 spec->adc_nids = stac925x_adc_nids;
3802 spec->mux_nids = stac925x_mux_nids;
3803 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003804 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003805 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003806 switch (codec->vendor_id) {
3807 case 0x83847632: /* STAC9202 */
3808 case 0x83847633: /* STAC9202D */
3809 case 0x83847636: /* STAC9251 */
3810 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003811 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003812 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01003813 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3814 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003815 break;
3816 default:
3817 spec->num_dmics = 0;
3818 break;
3819 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003820
3821 spec->init = stac925x_core_init;
3822 spec->mixer = stac925x_mixer;
3823
3824 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003825 if (!err) {
3826 if (spec->board_config < 0) {
3827 printk(KERN_WARNING "hda_codec: No auto-config is "
3828 "available, default to model=ref\n");
3829 spec->board_config = STAC_925x_REF;
3830 goto again;
3831 }
3832 err = -EINVAL;
3833 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003834 if (err < 0) {
3835 stac92xx_free(codec);
3836 return err;
3837 }
3838
3839 codec->patch_ops = stac92xx_patch_ops;
3840
3841 return 0;
3842}
3843
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003844static struct hda_input_mux stac92hd73xx_dmux = {
3845 .num_items = 4,
3846 .items = {
3847 { "Analog Inputs", 0x0b },
3848 { "CD", 0x08 },
3849 { "Digital Mic 1", 0x09 },
3850 { "Digital Mic 2", 0x0a },
3851 }
3852};
3853
3854static int patch_stac92hd73xx(struct hda_codec *codec)
3855{
3856 struct sigmatel_spec *spec;
3857 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3858 int err = 0;
3859
3860 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3861 if (spec == NULL)
3862 return -ENOMEM;
3863
3864 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02003865 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003866 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3867 spec->pin_nids = stac92hd73xx_pin_nids;
3868 spec->board_config = snd_hda_check_board_config(codec,
3869 STAC_92HD73XX_MODELS,
3870 stac92hd73xx_models,
3871 stac92hd73xx_cfg_tbl);
3872again:
3873 if (spec->board_config < 0) {
3874 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3875 " STAC92HD73XX, using BIOS defaults\n");
3876 err = stac92xx_save_bios_config_regs(codec);
3877 if (err < 0) {
3878 stac92xx_free(codec);
3879 return err;
3880 }
3881 spec->pin_configs = spec->bios_pin_configs;
3882 } else {
3883 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3884 stac92xx_set_config_regs(codec);
3885 }
3886
3887 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3888 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3889
3890 if (spec->multiout.num_dacs < 0) {
3891 printk(KERN_WARNING "hda_codec: Could not determine "
3892 "number of channels defaulting to DAC count\n");
3893 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3894 }
3895
3896 switch (spec->multiout.num_dacs) {
3897 case 0x3: /* 6 Channel */
3898 spec->mixer = stac92hd73xx_6ch_mixer;
3899 spec->init = stac92hd73xx_6ch_core_init;
3900 break;
3901 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003902 spec->mixer = stac92hd73xx_8ch_mixer;
3903 spec->init = stac92hd73xx_8ch_core_init;
3904 break;
3905 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003906 spec->mixer = stac92hd73xx_10ch_mixer;
3907 spec->init = stac92hd73xx_10ch_core_init;
3908 };
3909
3910 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3911 spec->aloopback_mask = 0x01;
3912 spec->aloopback_shift = 8;
3913
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003914 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003915 spec->mux_nids = stac92hd73xx_mux_nids;
3916 spec->adc_nids = stac92hd73xx_adc_nids;
3917 spec->dmic_nids = stac92hd73xx_dmic_nids;
3918 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003919 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003920
3921 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3922 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai16970552007-12-18 18:05:52 +01003923 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02003924 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003925 spec->dinput_mux = &stac92hd73xx_dmux;
3926 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003927 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003928 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003929
Matthew Ranostaya7662642008-02-21 07:51:14 +01003930 switch (spec->board_config) {
3931 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003932 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003933 switch (codec->subsystem_id) {
3934 case 0x1028025e: /* Analog Mics */
3935 case 0x1028025f:
3936 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3937 spec->num_dmics = 0;
3938 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003939 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003940 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003941 spec->init = dell_m6_core_init;
3942 /* fall-through */
3943 case 0x10280254:
3944 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003945 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3946 spec->num_dmics = 1;
3947 break;
3948 case 0x10280256: /* Both */
3949 case 0x10280057:
3950 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3951 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3952 spec->num_dmics = 1;
3953 break;
3954 }
3955 break;
3956 default:
3957 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3958 }
3959
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003960 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3961 spec->pwr_nids = stac92hd73xx_pwr_nids;
3962
Matthew Ranostayd9737752008-09-07 12:03:41 +02003963 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003964
3965 if (!err) {
3966 if (spec->board_config < 0) {
3967 printk(KERN_WARNING "hda_codec: No auto-config is "
3968 "available, default to model=ref\n");
3969 spec->board_config = STAC_92HD73XX_REF;
3970 goto again;
3971 }
3972 err = -EINVAL;
3973 }
3974
3975 if (err < 0) {
3976 stac92xx_free(codec);
3977 return err;
3978 }
3979
3980 codec->patch_ops = stac92xx_patch_ops;
3981
3982 return 0;
3983}
3984
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003985static struct hda_input_mux stac92hd83xxx_dmux = {
3986 .num_items = 3,
3987 .items = {
3988 { "Analog Inputs", 0x03 },
3989 { "Digital Mic 1", 0x04 },
3990 { "Digital Mic 2", 0x05 },
3991 }
3992};
3993
3994static int patch_stac92hd83xxx(struct hda_codec *codec)
3995{
3996 struct sigmatel_spec *spec;
3997 int err;
3998
3999 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4000 if (spec == NULL)
4001 return -ENOMEM;
4002
4003 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004004 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004005 spec->mono_nid = 0x19;
4006 spec->digbeep_nid = 0x21;
4007 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4008 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4009 spec->adc_nids = stac92hd83xxx_adc_nids;
4010 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4011 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4012 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4013 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4014
4015 spec->init = stac92hd83xxx_core_init;
4016 switch (codec->vendor_id) {
4017 case 0x111d7605:
4018 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4019 break;
4020 default:
4021 spec->num_pwrs--;
4022 spec->init++; /* switch to config #2 */
4023 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4024 }
4025
4026 spec->mixer = stac92hd83xxx_mixer;
4027 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4028 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4029 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4030 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4031 spec->dinput_mux = &stac92hd83xxx_dmux;
4032 spec->pin_nids = stac92hd83xxx_pin_nids;
4033 spec->board_config = snd_hda_check_board_config(codec,
4034 STAC_92HD83XXX_MODELS,
4035 stac92hd83xxx_models,
4036 stac92hd83xxx_cfg_tbl);
4037again:
4038 if (spec->board_config < 0) {
4039 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4040 " STAC92HD83XXX, using BIOS defaults\n");
4041 err = stac92xx_save_bios_config_regs(codec);
4042 if (err < 0) {
4043 stac92xx_free(codec);
4044 return err;
4045 }
4046 spec->pin_configs = spec->bios_pin_configs;
4047 } else {
4048 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4049 stac92xx_set_config_regs(codec);
4050 }
4051
4052 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4053 if (!err) {
4054 if (spec->board_config < 0) {
4055 printk(KERN_WARNING "hda_codec: No auto-config is "
4056 "available, default to model=ref\n");
4057 spec->board_config = STAC_92HD83XXX_REF;
4058 goto again;
4059 }
4060 err = -EINVAL;
4061 }
4062
4063 if (err < 0) {
4064 stac92xx_free(codec);
4065 return err;
4066 }
4067
4068 codec->patch_ops = stac92xx_patch_ops;
4069
4070 return 0;
4071}
4072
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004073#ifdef SND_HDA_NEEDS_RESUME
4074static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4075{
4076 struct sigmatel_spec *spec = codec->spec;
4077 int i;
4078 snd_hda_codec_write_cache(codec, codec->afg, 0,
4079 AC_VERB_SET_POWER_STATE, pwr);
4080
4081 msleep(1);
4082 for (i = 0; i < spec->num_adcs; i++) {
4083 snd_hda_codec_write_cache(codec,
4084 spec->adc_nids[i], 0,
4085 AC_VERB_SET_POWER_STATE, pwr);
4086 }
4087};
4088
4089static int stac92hd71xx_resume(struct hda_codec *codec)
4090{
4091 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4092 return stac92xx_resume(codec);
4093}
4094
4095static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4096{
4097 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4098 return 0;
4099};
4100
4101#endif
4102
4103static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4104 .build_controls = stac92xx_build_controls,
4105 .build_pcms = stac92xx_build_pcms,
4106 .init = stac92xx_init,
4107 .free = stac92xx_free,
4108 .unsol_event = stac92xx_unsol_event,
4109#ifdef SND_HDA_NEEDS_RESUME
4110 .resume = stac92hd71xx_resume,
4111 .suspend = stac92hd71xx_suspend,
4112#endif
4113};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004114
Matthew Ranostaye035b842007-11-06 11:53:55 +01004115static int patch_stac92hd71bxx(struct hda_codec *codec)
4116{
4117 struct sigmatel_spec *spec;
4118 int err = 0;
4119
4120 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4121 if (spec == NULL)
4122 return -ENOMEM;
4123
4124 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004125 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004126 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004127 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004128 spec->pin_nids = stac92hd71bxx_pin_nids;
4129 spec->board_config = snd_hda_check_board_config(codec,
4130 STAC_92HD71BXX_MODELS,
4131 stac92hd71bxx_models,
4132 stac92hd71bxx_cfg_tbl);
4133again:
4134 if (spec->board_config < 0) {
4135 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4136 " STAC92HD71BXX, using BIOS defaults\n");
4137 err = stac92xx_save_bios_config_regs(codec);
4138 if (err < 0) {
4139 stac92xx_free(codec);
4140 return err;
4141 }
4142 spec->pin_configs = spec->bios_pin_configs;
4143 } else {
4144 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4145 stac92xx_set_config_regs(codec);
4146 }
4147
Matthew Ranostay541eee82007-12-14 12:08:04 +01004148 switch (codec->vendor_id) {
4149 case 0x111d76b6: /* 4 Port without Analog Mixer */
4150 case 0x111d76b7:
4151 case 0x111d76b4: /* 6 Port without Analog Mixer */
4152 case 0x111d76b5:
4153 spec->mixer = stac92hd71bxx_mixer;
4154 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004155 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004156 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004157 case 0x111d7608: /* 5 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004158 if ((codec->revision_id & 0xf) == 0 ||
4159 (codec->revision_id & 0xf) == 1) {
4160#ifdef SND_HDA_NEEDS_RESUME
4161 codec->patch_ops = stac92hd71bxx_patch_ops;
4162#endif
4163 spec->stream_delay = 40; /* 40 milliseconds */
4164 }
4165
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004166 /* no output amps */
4167 spec->num_pwrs = 0;
4168 spec->mixer = stac92hd71bxx_analog_mixer;
4169
4170 /* disable VSW */
4171 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4172 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4173 break;
4174 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004175 if ((codec->revision_id & 0xf) == 1) {
4176#ifdef SND_HDA_NEEDS_RESUME
4177 codec->patch_ops = stac92hd71bxx_patch_ops;
4178#endif
4179 spec->stream_delay = 40; /* 40 milliseconds */
4180 }
4181
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004182 /* no output amps */
4183 spec->num_pwrs = 0;
4184 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004185 default:
4186 spec->mixer = stac92hd71bxx_analog_mixer;
4187 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004188 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004189 }
4190
4191 spec->aloopback_mask = 0x20;
4192 spec->aloopback_shift = 0;
4193
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004194 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004195 spec->gpio_mask = 0x01;
4196 spec->gpio_dir = 0x01;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004197 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004198
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004199 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004200 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004201 spec->mux_nids = stac92hd71bxx_mux_nids;
4202 spec->adc_nids = stac92hd71bxx_adc_nids;
4203 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004204 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004205 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004206 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004207
4208 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4209 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Takashi Iwai16970552007-12-18 18:05:52 +01004210 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004211
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004212 switch (spec->board_config) {
4213 case STAC_HP_M4:
4214 spec->num_dmics = 0;
4215 spec->num_smuxes = 1;
4216 spec->num_dmuxes = 0;
4217
4218 /* enable internal microphone */
4219 snd_hda_codec_write_cache(codec, 0x0e, 0,
4220 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
4221 break;
4222 default:
4223 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4224 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4225 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4226 };
4227
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004228 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004229 spec->multiout.hp_nid = 0x11;
4230 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
4231
4232 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4233 if (!err) {
4234 if (spec->board_config < 0) {
4235 printk(KERN_WARNING "hda_codec: No auto-config is "
4236 "available, default to model=ref\n");
4237 spec->board_config = STAC_92HD71BXX_REF;
4238 goto again;
4239 }
4240 err = -EINVAL;
4241 }
4242
4243 if (err < 0) {
4244 stac92xx_free(codec);
4245 return err;
4246 }
4247
Matthew Ranostaye035b842007-11-06 11:53:55 +01004248 return 0;
4249};
4250
Matt2f2f4252005-04-13 14:45:30 +02004251static int patch_stac922x(struct hda_codec *codec)
4252{
4253 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004254 int err;
Matt2f2f4252005-04-13 14:45:30 +02004255
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004256 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004257 if (spec == NULL)
4258 return -ENOMEM;
4259
4260 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004261 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004262 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004263 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4264 stac922x_models,
4265 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004266 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004267 spec->gpio_mask = spec->gpio_dir = 0x03;
4268 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004269 /* Intel Macs have all same PCI SSID, so we need to check
4270 * codec SSID to distinguish the exact models
4271 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004272 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004273 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004274
4275 case 0x106b0800:
4276 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004277 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004278 case 0x106b0600:
4279 case 0x106b0700:
4280 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004281 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004282 case 0x106b0e00:
4283 case 0x106b0f00:
4284 case 0x106b1600:
4285 case 0x106b1700:
4286 case 0x106b0200:
4287 case 0x106b1e00:
4288 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004289 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004290 case 0x106b1a00:
4291 case 0x00000100:
4292 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004293 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004294 case 0x106b0a00:
4295 case 0x106b2200:
4296 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004297 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004298 default:
4299 spec->board_config = STAC_INTEL_MAC_V3;
4300 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004301 }
4302 }
4303
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004304 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004305 if (spec->board_config < 0) {
4306 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4307 "using BIOS defaults\n");
4308 err = stac92xx_save_bios_config_regs(codec);
4309 if (err < 0) {
4310 stac92xx_free(codec);
4311 return err;
4312 }
4313 spec->pin_configs = spec->bios_pin_configs;
4314 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004315 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4316 stac92xx_set_config_regs(codec);
4317 }
Matt2f2f4252005-04-13 14:45:30 +02004318
Matt2f2f4252005-04-13 14:45:30 +02004319 spec->adc_nids = stac922x_adc_nids;
4320 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004321 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004322 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004323 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004324 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004325
4326 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004327 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004328
4329 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004330
Matt Porter3cc08dc2006-01-23 15:27:49 +01004331 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004332 if (!err) {
4333 if (spec->board_config < 0) {
4334 printk(KERN_WARNING "hda_codec: No auto-config is "
4335 "available, default to model=ref\n");
4336 spec->board_config = STAC_D945_REF;
4337 goto again;
4338 }
4339 err = -EINVAL;
4340 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004341 if (err < 0) {
4342 stac92xx_free(codec);
4343 return err;
4344 }
4345
4346 codec->patch_ops = stac92xx_patch_ops;
4347
Takashi Iwai807a46362007-05-29 19:01:37 +02004348 /* Fix Mux capture level; max to 2 */
4349 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4350 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4351 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4352 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4353 (0 << AC_AMPCAP_MUTE_SHIFT));
4354
Matt Porter3cc08dc2006-01-23 15:27:49 +01004355 return 0;
4356}
4357
4358static int patch_stac927x(struct hda_codec *codec)
4359{
4360 struct sigmatel_spec *spec;
4361 int err;
4362
4363 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4364 if (spec == NULL)
4365 return -ENOMEM;
4366
4367 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004368 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004369 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004370 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4371 stac927x_models,
4372 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004373 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004374 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4375 if (spec->board_config < 0)
4376 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4377 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004378 err = stac92xx_save_bios_config_regs(codec);
4379 if (err < 0) {
4380 stac92xx_free(codec);
4381 return err;
4382 }
4383 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004384 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004385 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4386 stac92xx_set_config_regs(codec);
4387 }
4388
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004389 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004390 spec->adc_nids = stac927x_adc_nids;
4391 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4392 spec->mux_nids = stac927x_mux_nids;
4393 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004394 spec->smux_nids = stac927x_smux_nids;
4395 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004396 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004397 spec->multiout.dac_nids = spec->dac_nids;
4398
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004399 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004400 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004401 case STAC_D965_5ST:
4402 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004403 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004404 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004405 spec->num_dmics = 0;
4406
Tobin Davis93ed1502006-09-01 21:03:12 +02004407 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004408 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004409 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004410 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004411 switch (codec->subsystem_id) {
4412 case 0x10280209:
4413 case 0x1028022e:
4414 /* correct the device field to SPDIF out */
4415 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4416 break;
4417 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004418 /* configure the analog microphone on some laptops */
4419 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004420 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004421 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004422 /* correct the front input jack as a mic */
4423 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4424 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004425 case STAC_DELL_3ST:
4426 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004427 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004428 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004429 spec->dmic_nids = stac927x_dmic_nids;
4430 spec->num_dmics = STAC927X_NUM_DMICS;
4431
Tobin Davis93ed1502006-09-01 21:03:12 +02004432 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004433 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004434 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01004435 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004436 break;
4437 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004438 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004439 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004440 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004441 spec->num_dmics = 0;
4442
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004443 spec->init = stac927x_core_init;
4444 spec->mixer = stac927x_mixer;
4445 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004446
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004447 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004448 spec->aloopback_mask = 0x40;
4449 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004450
Matt Porter3cc08dc2006-01-23 15:27:49 +01004451 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004452 if (!err) {
4453 if (spec->board_config < 0) {
4454 printk(KERN_WARNING "hda_codec: No auto-config is "
4455 "available, default to model=ref\n");
4456 spec->board_config = STAC_D965_REF;
4457 goto again;
4458 }
4459 err = -EINVAL;
4460 }
Mattc7d4b2f2005-06-27 14:59:41 +02004461 if (err < 0) {
4462 stac92xx_free(codec);
4463 return err;
4464 }
Matt2f2f4252005-04-13 14:45:30 +02004465
4466 codec->patch_ops = stac92xx_patch_ops;
4467
Takashi Iwai52987652008-01-16 16:09:47 +01004468 /*
4469 * !!FIXME!!
4470 * The STAC927x seem to require fairly long delays for certain
4471 * command sequences. With too short delays (even if the answer
4472 * is set to RIRB properly), it results in the silence output
4473 * on some hardwares like Dell.
4474 *
4475 * The below flag enables the longer delay (see get_response
4476 * in hda_intel.c).
4477 */
4478 codec->bus->needs_damn_long_delay = 1;
4479
Matt2f2f4252005-04-13 14:45:30 +02004480 return 0;
4481}
4482
Matt Porterf3302a52006-07-31 12:49:34 +02004483static int patch_stac9205(struct hda_codec *codec)
4484{
4485 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004486 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004487
4488 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4489 if (spec == NULL)
4490 return -ENOMEM;
4491
4492 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004493 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004494 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004495 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4496 stac9205_models,
4497 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004498 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004499 if (spec->board_config < 0) {
4500 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4501 err = stac92xx_save_bios_config_regs(codec);
4502 if (err < 0) {
4503 stac92xx_free(codec);
4504 return err;
4505 }
4506 spec->pin_configs = spec->bios_pin_configs;
4507 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004508 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4509 stac92xx_set_config_regs(codec);
4510 }
4511
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004512 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004513 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004514 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004515 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004516 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004517 spec->smux_nids = stac9205_smux_nids;
4518 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004519 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004520 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004521 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01004522 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004523 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004524
4525 spec->init = stac9205_core_init;
4526 spec->mixer = stac9205_mixer;
4527
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004528 spec->aloopback_mask = 0x40;
4529 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004530 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004531
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004532 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004533 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004534 /* Enable SPDIF in/out */
4535 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4536 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004537
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004538 /* Enable unsol response for GPIO4/Dock HP connection */
4539 snd_hda_codec_write(codec, codec->afg, 0,
4540 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4541 snd_hda_codec_write_cache(codec, codec->afg, 0,
4542 AC_VERB_SET_UNSOLICITED_ENABLE,
4543 (AC_USRSP_EN | STAC_HP_EVENT));
4544
4545 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004546 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004547 spec->gpio_mask = 0x1b;
4548 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004549 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004550 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004551 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004552 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004553 break;
4554 default:
4555 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004556 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004557 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004558 break;
4559 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004560
Matt Porterf3302a52006-07-31 12:49:34 +02004561 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004562 if (!err) {
4563 if (spec->board_config < 0) {
4564 printk(KERN_WARNING "hda_codec: No auto-config is "
4565 "available, default to model=ref\n");
4566 spec->board_config = STAC_9205_REF;
4567 goto again;
4568 }
4569 err = -EINVAL;
4570 }
Matt Porterf3302a52006-07-31 12:49:34 +02004571 if (err < 0) {
4572 stac92xx_free(codec);
4573 return err;
4574 }
4575
4576 codec->patch_ops = stac92xx_patch_ops;
4577
4578 return 0;
4579}
4580
Matt2f2f4252005-04-13 14:45:30 +02004581/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004582 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004583 */
4584
Guillaume Munch99ccc562006-08-16 19:35:12 +02004585/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004586static hda_nid_t vaio_dacs[] = { 0x2 };
4587#define VAIO_HP_DAC 0x5
4588static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4589static hda_nid_t vaio_mux_nids[] = { 0x15 };
4590
4591static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004592 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004593 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004594 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004595 { "Mic Jack", 0x1 },
4596 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004597 { "PCM", 0x3 },
4598 }
4599};
4600
4601static struct hda_verb vaio_init[] = {
4602 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004603 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004604 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4605 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4606 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4607 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004608 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004609 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4610 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4611 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4612 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4613 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4614 {}
4615};
4616
Guillaume Munch6d859062006-08-22 17:15:47 +02004617static struct hda_verb vaio_ar_init[] = {
4618 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4619 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4620 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4621 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4622/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004624 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004625 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4626 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4627/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4628 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4629 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4630 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4631 {}
4632};
4633
Takashi Iwaidb064e52006-03-16 16:04:58 +01004634/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004635static struct hda_bind_ctls vaio_bind_master_vol = {
4636 .ops = &snd_hda_bind_vol,
4637 .values = {
4638 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4639 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4640 0
4641 },
4642};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004643
4644/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004645static struct hda_bind_ctls vaio_bind_master_sw = {
4646 .ops = &snd_hda_bind_sw,
4647 .values = {
4648 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4649 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4650 0,
4651 },
4652};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004653
4654static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004655 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4656 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004657 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4658 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4659 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4660 {
4661 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4662 .name = "Capture Source",
4663 .count = 1,
4664 .info = stac92xx_mux_enum_info,
4665 .get = stac92xx_mux_enum_get,
4666 .put = stac92xx_mux_enum_put,
4667 },
4668 {}
4669};
4670
Guillaume Munch6d859062006-08-22 17:15:47 +02004671static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004672 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4673 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004674 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4675 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4676 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4677 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4678 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4679 {
4680 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4681 .name = "Capture Source",
4682 .count = 1,
4683 .info = stac92xx_mux_enum_info,
4684 .get = stac92xx_mux_enum_get,
4685 .put = stac92xx_mux_enum_put,
4686 },
4687 {}
4688};
4689
4690static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004691 .build_controls = stac92xx_build_controls,
4692 .build_pcms = stac92xx_build_pcms,
4693 .init = stac92xx_init,
4694 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004695#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004696 .resume = stac92xx_resume,
4697#endif
4698};
4699
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004700static int stac9872_vaio_init(struct hda_codec *codec)
4701{
4702 int err;
4703
4704 err = stac92xx_init(codec);
4705 if (err < 0)
4706 return err;
4707 if (codec->patch_ops.unsol_event)
4708 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4709 return 0;
4710}
4711
4712static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4713{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004714 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004715 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4716 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4717 } else {
4718 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4719 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4720 }
4721}
4722
4723static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4724{
4725 switch (res >> 26) {
4726 case STAC_HP_EVENT:
4727 stac9872_vaio_hp_detect(codec, res);
4728 break;
4729 }
4730}
4731
4732static struct hda_codec_ops stac9872_vaio_patch_ops = {
4733 .build_controls = stac92xx_build_controls,
4734 .build_pcms = stac92xx_build_pcms,
4735 .init = stac9872_vaio_init,
4736 .free = stac92xx_free,
4737 .unsol_event = stac9872_vaio_unsol_event,
4738#ifdef CONFIG_PM
4739 .resume = stac92xx_resume,
4740#endif
4741};
4742
Guillaume Munch6d859062006-08-22 17:15:47 +02004743enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4744 CXD9872RD_VAIO,
4745 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4746 STAC9872AK_VAIO,
4747 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4748 STAC9872K_VAIO,
4749 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004750 CXD9872AKD_VAIO,
4751 STAC_9872_MODELS,
4752};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004753
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004754static const char *stac9872_models[STAC_9872_MODELS] = {
4755 [CXD9872RD_VAIO] = "vaio",
4756 [CXD9872AKD_VAIO] = "vaio-ar",
4757};
4758
4759static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4760 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4761 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4762 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004763 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004764 {}
4765};
4766
Guillaume Munch6d859062006-08-22 17:15:47 +02004767static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004768{
4769 struct sigmatel_spec *spec;
4770 int board_config;
4771
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004772 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4773 stac9872_models,
4774 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004775 if (board_config < 0)
4776 /* unknown config, let generic-parser do its job... */
4777 return snd_hda_parse_generic_codec(codec);
4778
4779 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4780 if (spec == NULL)
4781 return -ENOMEM;
4782
4783 codec->spec = spec;
4784 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004785 case CXD9872RD_VAIO:
4786 case STAC9872AK_VAIO:
4787 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004788 spec->mixer = vaio_mixer;
4789 spec->init = vaio_init;
4790 spec->multiout.max_channels = 2;
4791 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4792 spec->multiout.dac_nids = vaio_dacs;
4793 spec->multiout.hp_nid = VAIO_HP_DAC;
4794 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4795 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004796 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004797 spec->input_mux = &vaio_mux;
4798 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004799 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004800 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004801
4802 case CXD9872AKD_VAIO:
4803 spec->mixer = vaio_ar_mixer;
4804 spec->init = vaio_ar_init;
4805 spec->multiout.max_channels = 2;
4806 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4807 spec->multiout.dac_nids = vaio_dacs;
4808 spec->multiout.hp_nid = VAIO_HP_DAC;
4809 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004810 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004811 spec->adc_nids = vaio_adcs;
4812 spec->input_mux = &vaio_mux;
4813 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004814 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004815 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004816 }
4817
Takashi Iwaidb064e52006-03-16 16:04:58 +01004818 return 0;
4819}
4820
4821
4822/*
Matt2f2f4252005-04-13 14:45:30 +02004823 * patch entries
4824 */
4825struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4826 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4827 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4828 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4829 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4830 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4831 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4832 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004833 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4834 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4835 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4836 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4837 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4838 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004839 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4840 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4841 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4842 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4843 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4844 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4845 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4846 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4847 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4848 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004849 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4850 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4851 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4852 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4853 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4854 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02004855 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
4856 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004857 /* The following does not take into account .id=0x83847661 when subsys =
4858 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4859 * currently not fully supported.
4860 */
4861 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4862 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4863 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004864 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4865 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4866 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4867 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4868 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4869 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4870 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4871 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004872 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004873 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
4874 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004875 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01004876 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4877 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004878 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004879 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4880 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4881 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4882 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4883 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4884 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4885 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4886 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004887 {} /* terminator */
4888};