blob: 4fa5189264b74c7954aa7761842af4be8190a542 [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>
Matthew Ranostay45a6ac12008-10-15 14:45:38 -040033#include <sound/jack.h>
Matt2f2f4252005-04-13 14:45:30 +020034#include "hda_codec.h"
35#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010036#include "hda_patch.h"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020037#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020038
Matthew Ranostayc39555d2008-11-14 17:46:22 -050039#define STAC_VREF_EVENT 0x00
Matthew Ranostay74aeaab2008-10-25 01:06:04 -040040#define STAC_INSERT_EVENT 0x10
Matthew Ranostaya64135a2008-01-10 16:55:06 +010041#define STAC_PWR_EVENT 0x20
42#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020043
Takashi Iwaif5fcc132006-11-24 17:07:44 +010044enum {
45 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010046 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020047 STAC_9200_DELL_D21,
48 STAC_9200_DELL_D22,
49 STAC_9200_DELL_D23,
50 STAC_9200_DELL_M21,
51 STAC_9200_DELL_M22,
52 STAC_9200_DELL_M23,
53 STAC_9200_DELL_M24,
54 STAC_9200_DELL_M25,
55 STAC_9200_DELL_M26,
56 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020057 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010058 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010059 STAC_9200_MODELS
60};
61
62enum {
63 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020064 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020065 STAC_9205_DELL_M43,
66 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010067 STAC_9205_MODELS
68};
69
70enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010071 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010072 STAC_DELL_M6,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -050073 STAC_DELL_EQ,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010074 STAC_92HD73XX_MODELS
75};
76
77enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020078 STAC_92HD83XXX_REF,
79 STAC_92HD83XXX_MODELS
80};
81
82enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010083 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010084 STAC_DELL_M4_1,
85 STAC_DELL_M4_2,
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -050086 STAC_DELL_M4_3,
Matthew Ranostay6a14f582008-09-12 12:02:30 -040087 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010088 STAC_92HD71BXX_MODELS
89};
90
91enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010092 STAC_925x_REF,
93 STAC_M2_2,
94 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020095 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010096 STAC_925x_MODELS
97};
98
99enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100100 STAC_D945_REF,
101 STAC_D945GTP3,
102 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200103 STAC_INTEL_MAC_V1,
104 STAC_INTEL_MAC_V2,
105 STAC_INTEL_MAC_V3,
106 STAC_INTEL_MAC_V4,
107 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800108 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
109 * is given, one of the above models will be
110 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200111 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100112 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100113 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100114 STAC_MACBOOK_PRO_V1,
115 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200116 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200117 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300118 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200119 STAC_922X_DELL_D81,
120 STAC_922X_DELL_D82,
121 STAC_922X_DELL_M81,
122 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100123 STAC_922X_MODELS
124};
125
126enum {
127 STAC_D965_REF,
128 STAC_D965_3ST,
129 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200130 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100131 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100132 STAC_927X_MODELS
133};
Matt Porter403d1942005-11-29 15:00:51 +0100134
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400135struct sigmatel_event {
136 hda_nid_t nid;
137 int data;
138};
139
140struct sigmatel_jack {
141 hda_nid_t nid;
142 int type;
143 struct snd_jack *jack;
144};
145
Matt2f2f4252005-04-13 14:45:30 +0200146struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100147 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200148 unsigned int num_mixers;
149
Matt Porter403d1942005-11-29 15:00:51 +0100150 int board_config;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -0500151 unsigned int eapd_switch: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200152 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100153 unsigned int line_switch: 1;
154 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100155 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100156 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400157 unsigned int spdif_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200158
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100159 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200160 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100161 unsigned int gpio_mask;
162 unsigned int gpio_dir;
163 unsigned int gpio_data;
164 unsigned int gpio_mute;
165
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200166 /* stream */
167 unsigned int stream_delay;
168
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100169 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100170 unsigned char aloopback_mask;
171 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200172
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100173 /* power management */
174 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200175 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100176 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100177 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100178
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400179 /* jack detection */
180 struct snd_array jacks;
181
182 /* events */
183 struct snd_array events;
184
Matt2f2f4252005-04-13 14:45:30 +0200185 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100186 struct hda_input_mux *mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400187 struct hda_input_mux *amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100188 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200189 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100190 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200191
192 /* capture */
193 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200194 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200195 hda_nid_t *mux_nids;
196 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200197 hda_nid_t *dmic_nids;
198 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100199 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100200 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200201 hda_nid_t *smux_nids;
202 unsigned int num_smuxes;
Matthew Ranostay65973632008-09-16 10:39:37 -0400203 const char **spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200204
Mattdabbed62005-06-14 10:19:34 +0200205 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100206 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200207 hda_nid_t anabeep_nid;
208 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200209
Matt2f2f4252005-04-13 14:45:30 +0200210 /* pin widgets */
211 hda_nid_t *pin_nids;
212 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200213 unsigned int *pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200214
215 /* codec specific stuff */
216 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100217 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200218
219 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200220 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100221 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200222 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100223 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200224 struct hda_input_mux *sinput_mux;
225 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400226 unsigned int cur_amux;
227 hda_nid_t *amp_nids;
228 unsigned int num_amps;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200229 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200230
Matt Porter403d1942005-11-29 15:00:51 +0100231 /* i/o switches */
232 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200233 unsigned int clfe_swap;
Takashi Iwaid7a89432008-11-12 09:48:04 +0100234 unsigned int hp_switch; /* NID of HP as line-out */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200235 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200236
Mattc7d4b2f2005-06-27 14:59:41 +0200237 struct hda_pcm pcm_rec[2]; /* PCM information */
238
239 /* dynamic controls and input_mux */
240 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200241 struct snd_array kctls;
Matt Porter8b657272006-10-26 17:12:59 +0200242 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200243 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200244 struct hda_input_mux private_smux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400245 struct hda_input_mux private_amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100246 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200247};
248
249static hda_nid_t stac9200_adc_nids[1] = {
250 0x03,
251};
252
253static hda_nid_t stac9200_mux_nids[1] = {
254 0x0c,
255};
256
257static hda_nid_t stac9200_dac_nids[1] = {
258 0x02,
259};
260
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100261static hda_nid_t stac92hd73xx_pwr_nids[8] = {
262 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
263 0x0f, 0x10, 0x11
264};
265
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400266static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
267 0x26, 0,
268};
269
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100270static hda_nid_t stac92hd73xx_adc_nids[2] = {
271 0x1a, 0x1b
272};
273
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400274#define DELL_M6_AMP 2
275static hda_nid_t stac92hd73xx_amp_nids[3] = {
276 0x0b, 0x0c, 0x0e
Matthew Ranostay89385032008-09-11 09:49:39 -0400277};
278
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100279#define STAC92HD73XX_NUM_DMICS 2
280static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
281 0x13, 0x14, 0
282};
283
284#define STAC92HD73_DAC_COUNT 5
285static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
286 0x15, 0x16, 0x17, 0x18, 0x19,
287};
288
289static hda_nid_t stac92hd73xx_mux_nids[4] = {
290 0x28, 0x29, 0x2a, 0x2b,
291};
292
293static hda_nid_t stac92hd73xx_dmux_nids[2] = {
294 0x20, 0x21,
295};
296
Matthew Ranostayd9737752008-09-07 12:03:41 +0200297static hda_nid_t stac92hd73xx_smux_nids[2] = {
298 0x22, 0x23,
299};
300
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200301#define STAC92HD83XXX_NUM_DMICS 2
302static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
303 0x11, 0x12, 0
304};
305
306#define STAC92HD81_DAC_COUNT 2
307#define STAC92HD83_DAC_COUNT 3
308static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
309 0x13, 0x14, 0x22,
310};
311
312static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
313 0x17, 0x18,
314};
315
316static hda_nid_t stac92hd83xxx_adc_nids[2] = {
317 0x15, 0x16,
318};
319
320static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
321 0xa, 0xb, 0xd, 0xe,
322};
323
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400324static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
325 0x1e, 0,
326};
327
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200328static unsigned int stac92hd83xxx_pwr_mapping[4] = {
329 0x03, 0x0c, 0x10, 0x40,
330};
331
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100332static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
333 0x0a, 0x0d, 0x0f
334};
335
Matthew Ranostaye035b842007-11-06 11:53:55 +0100336static hda_nid_t stac92hd71bxx_adc_nids[2] = {
337 0x12, 0x13,
338};
339
340static hda_nid_t stac92hd71bxx_mux_nids[2] = {
341 0x1a, 0x1b
342};
343
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400344static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
345 0x1c, 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100346};
347
Matthew Ranostayd9737752008-09-07 12:03:41 +0200348static hda_nid_t stac92hd71bxx_smux_nids[2] = {
349 0x24, 0x25,
350};
351
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100352static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100353 0x10, /*0x11, */
354};
355
356#define STAC92HD71BXX_NUM_DMICS 2
357static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
358 0x18, 0x19, 0
359};
360
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400361static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
362 0x22, 0
363};
364
Tobin Davis8e21c342007-01-08 11:04:17 +0100365static hda_nid_t stac925x_adc_nids[1] = {
366 0x03,
367};
368
369static hda_nid_t stac925x_mux_nids[1] = {
370 0x0f,
371};
372
373static hda_nid_t stac925x_dac_nids[1] = {
374 0x02,
375};
376
Takashi Iwaif6e98522007-10-16 14:27:04 +0200377#define STAC925X_NUM_DMICS 1
378static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
379 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200380};
381
Takashi Iwai1697055e2007-12-18 18:05:52 +0100382static hda_nid_t stac925x_dmux_nids[1] = {
383 0x14,
384};
385
Matt2f2f4252005-04-13 14:45:30 +0200386static hda_nid_t stac922x_adc_nids[2] = {
387 0x06, 0x07,
388};
389
390static hda_nid_t stac922x_mux_nids[2] = {
391 0x12, 0x13,
392};
393
Matt Porter3cc08dc2006-01-23 15:27:49 +0100394static hda_nid_t stac927x_adc_nids[3] = {
395 0x07, 0x08, 0x09
396};
397
398static hda_nid_t stac927x_mux_nids[3] = {
399 0x15, 0x16, 0x17
400};
401
Matthew Ranostayd9737752008-09-07 12:03:41 +0200402static hda_nid_t stac927x_smux_nids[1] = {
403 0x21,
404};
405
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100406static hda_nid_t stac927x_dac_nids[6] = {
407 0x02, 0x03, 0x04, 0x05, 0x06, 0
408};
409
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100410static hda_nid_t stac927x_dmux_nids[1] = {
411 0x1b,
412};
413
Matthew Ranostay7f168592007-10-18 17:38:17 +0200414#define STAC927X_NUM_DMICS 2
415static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
416 0x13, 0x14, 0
417};
418
Matthew Ranostay65973632008-09-16 10:39:37 -0400419static const char *stac927x_spdif_labels[5] = {
420 "Digital Playback", "ADAT", "Analog Mux 1",
421 "Analog Mux 2", "Analog Mux 3"
422};
423
Matt Porterf3302a52006-07-31 12:49:34 +0200424static hda_nid_t stac9205_adc_nids[2] = {
425 0x12, 0x13
426};
427
428static hda_nid_t stac9205_mux_nids[2] = {
429 0x19, 0x1a
430};
431
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100432static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100433 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100434};
435
Matthew Ranostayd9737752008-09-07 12:03:41 +0200436static hda_nid_t stac9205_smux_nids[1] = {
437 0x21,
438};
439
Takashi Iwaif6e98522007-10-16 14:27:04 +0200440#define STAC9205_NUM_DMICS 2
441static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
442 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200443};
444
Mattc7d4b2f2005-06-27 14:59:41 +0200445static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200446 0x08, 0x09, 0x0d, 0x0e,
447 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200448};
449
Tobin Davis8e21c342007-01-08 11:04:17 +0100450static hda_nid_t stac925x_pin_nids[8] = {
451 0x07, 0x08, 0x0a, 0x0b,
452 0x0c, 0x0d, 0x10, 0x11,
453};
454
Matt2f2f4252005-04-13 14:45:30 +0200455static hda_nid_t stac922x_pin_nids[10] = {
456 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
457 0x0f, 0x10, 0x11, 0x15, 0x1b,
458};
459
Matthew Ranostaya7662642008-02-21 07:51:14 +0100460static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100461 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
462 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200463 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100464};
465
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200466static hda_nid_t stac92hd83xxx_pin_nids[14] = {
467 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
468 0x0f, 0x10, 0x11, 0x12, 0x13,
469 0x1d, 0x1e, 0x1f, 0x20
470};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400471static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100472 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
473 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400474 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100475};
476
Matt Porter3cc08dc2006-01-23 15:27:49 +0100477static hda_nid_t stac927x_pin_nids[14] = {
478 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
479 0x0f, 0x10, 0x11, 0x12, 0x13,
480 0x14, 0x21, 0x22, 0x23,
481};
482
Matt Porterf3302a52006-07-31 12:49:34 +0200483static hda_nid_t stac9205_pin_nids[12] = {
484 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
485 0x0f, 0x14, 0x16, 0x17, 0x18,
486 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200487};
488
Matthew Ranostay89385032008-09-11 09:49:39 -0400489#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
490
491static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
492 struct snd_ctl_elem_value *ucontrol)
493{
494 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
495 struct sigmatel_spec *spec = codec->spec;
496 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
497
498 kcontrol->private_value ^= get_amp_nid(kcontrol);
499 kcontrol->private_value |= nid;
500
501 return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
502}
503
504static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
505 struct snd_ctl_elem_value *ucontrol)
506{
507 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
508 struct sigmatel_spec *spec = codec->spec;
509 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
510
511 kcontrol->private_value ^= get_amp_nid(kcontrol);
512 kcontrol->private_value |= nid;
513
514 return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
515}
516
Matt Porter8b657272006-10-26 17:12:59 +0200517static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
518 struct snd_ctl_elem_info *uinfo)
519{
520 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
521 struct sigmatel_spec *spec = codec->spec;
522 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
523}
524
525static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_value *ucontrol)
527{
528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
529 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100530 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200531
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100532 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200533 return 0;
534}
535
536static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_value *ucontrol)
538{
539 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
540 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100541 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200542
543 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100544 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200545}
546
Matthew Ranostayd9737752008-09-07 12:03:41 +0200547static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
548 struct snd_ctl_elem_info *uinfo)
549{
550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
551 struct sigmatel_spec *spec = codec->spec;
552 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
553}
554
555static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
556 struct snd_ctl_elem_value *ucontrol)
557{
558 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
559 struct sigmatel_spec *spec = codec->spec;
560 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
561
562 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
563 return 0;
564}
565
566static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
567 struct snd_ctl_elem_value *ucontrol)
568{
569 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
570 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400571 struct hda_input_mux *smux = &spec->private_smux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200572 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400573 int err, val;
574 hda_nid_t nid;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200575
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400576 err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200577 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400578 if (err < 0)
579 return err;
580
581 if (spec->spdif_mute) {
582 if (smux_idx == 0)
583 nid = spec->multiout.dig_out_nid;
584 else
585 nid = codec->slave_dig_outs[smux_idx - 1];
586 if (spec->cur_smux[smux_idx] == smux->num_items - 1)
587 val = AMP_OUT_MUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400588 else
Takashi Iwaic1e99bd2008-10-29 08:03:42 +0100589 val = AMP_OUT_UNMUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400590 /* un/mute SPDIF out */
591 snd_hda_codec_write_cache(codec, nid, 0,
592 AC_VERB_SET_AMP_GAIN_MUTE, val);
593 }
594 return 0;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200595}
596
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100597static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200598{
599 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
600 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200601 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200602}
603
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100604static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200605{
606 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
607 struct sigmatel_spec *spec = codec->spec;
608 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
609
610 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
611 return 0;
612}
613
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100614static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200615{
616 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
617 struct sigmatel_spec *spec = codec->spec;
618 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
619
Mattc7d4b2f2005-06-27 14:59:41 +0200620 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200621 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
622}
623
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100624static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
625 struct snd_ctl_elem_info *uinfo)
626{
627 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
628 struct sigmatel_spec *spec = codec->spec;
629 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
630}
631
632static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
633 struct snd_ctl_elem_value *ucontrol)
634{
635 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
636 struct sigmatel_spec *spec = codec->spec;
637
638 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
639 return 0;
640}
641
642static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
643 struct snd_ctl_elem_value *ucontrol)
644{
645 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
646 struct sigmatel_spec *spec = codec->spec;
647
648 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
649 spec->mono_nid, &spec->cur_mmux);
650}
651
Matthew Ranostay89385032008-09-11 09:49:39 -0400652static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
653 struct snd_ctl_elem_info *uinfo)
654{
655 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
656 struct sigmatel_spec *spec = codec->spec;
657 return snd_hda_input_mux_info(spec->amp_mux, uinfo);
658}
659
660static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
661 struct snd_ctl_elem_value *ucontrol)
662{
663 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
664 struct sigmatel_spec *spec = codec->spec;
665
666 ucontrol->value.enumerated.item[0] = spec->cur_amux;
667 return 0;
668}
669
670static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
671 struct snd_ctl_elem_value *ucontrol)
672{
673 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
674 struct sigmatel_spec *spec = codec->spec;
675 struct snd_kcontrol *ctl =
676 snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
677 if (!ctl)
678 return -EINVAL;
679
680 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
681 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
682
683 return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
684 0, &spec->cur_amux);
685}
686
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200687#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
688
689static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
690 struct snd_ctl_elem_value *ucontrol)
691{
692 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100693 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200694 struct sigmatel_spec *spec = codec->spec;
695
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100696 ucontrol->value.integer.value[0] = !!(spec->aloopback &
697 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200698 return 0;
699}
700
701static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
702 struct snd_ctl_elem_value *ucontrol)
703{
704 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
705 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100706 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200707 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100708 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200709
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100710 idx_val = spec->aloopback_mask << idx;
711 if (ucontrol->value.integer.value[0])
712 val = spec->aloopback | idx_val;
713 else
714 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100715 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200716 return 0;
717
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100718 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200719
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100720 /* Only return the bits defined by the shift value of the
721 * first two bytes of the mask
722 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200723 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100724 kcontrol->private_value & 0xFFFF, 0x0);
725 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200726
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100727 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200728 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100729 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200730 } else {
731 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200733 }
734
735 snd_hda_codec_write_cache(codec, codec->afg, 0,
736 kcontrol->private_value >> 16, dac_mode);
737
738 return 1;
739}
740
Mattc7d4b2f2005-06-27 14:59:41 +0200741static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200742 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200743 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200744 {}
745};
746
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200747static struct hda_verb stac9200_eapd_init[] = {
748 /* set dac0mux for dac converter */
749 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
750 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
751 {}
752};
753
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100754static struct hda_verb stac92hd73xx_6ch_core_init[] = {
755 /* set master volume and direct control */
756 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
757 /* setup audio connections */
758 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
759 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
760 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
761 /* setup adcs to point to mixer */
762 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
763 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100764 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
765 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
766 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
767 /* setup import muxs */
768 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
769 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
770 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
771 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
772 {}
773};
774
Matthew Ranostayd654a662008-03-14 08:46:51 +0100775static struct hda_verb dell_eq_core_init[] = {
776 /* set master volume to max value without distortion
777 * and direct control */
778 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
779 /* setup audio connections */
780 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
Matthew Ranostayf7cf0a72008-09-13 10:36:58 -0400781 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
782 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayd654a662008-03-14 08:46:51 +0100783 /* setup adcs to point to mixer */
784 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
785 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
786 /* setup import muxs */
787 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
788 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
789 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
790 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
791 {}
792};
793
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100794static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -0500795 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100796 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100797 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
798 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100799 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
800 /* setup adcs to point to mixer */
801 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
802 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
803 /* setup import muxs */
804 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
805 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
806 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
807 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
808 {}
809};
810
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100811static struct hda_verb stac92hd73xx_8ch_core_init[] = {
812 /* set master volume and direct control */
813 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
814 /* setup audio connections */
815 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
816 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
817 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
818 /* connect hp ports to dac3 */
819 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
820 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
821 /* setup adcs to point to mixer */
822 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
823 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100824 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
825 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
826 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
827 /* setup import muxs */
828 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
829 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
830 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
831 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
832 {}
833};
834
835static struct hda_verb stac92hd73xx_10ch_core_init[] = {
836 /* set master volume and direct control */
837 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
838 /* setup audio connections */
839 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
840 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
841 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
842 /* dac3 is connected to import3 mux */
843 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
844 /* connect hp ports to dac4 */
845 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
846 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
847 /* setup adcs to point to mixer */
848 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
849 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100850 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
851 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
852 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
853 /* setup import muxs */
854 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
855 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
856 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
857 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
858 {}
859};
860
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200861static struct hda_verb stac92hd83xxx_core_init[] = {
862 /* start of config #1 */
863 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
864
865 /* start of config #2 */
866 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
867 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
868 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
869
870 /* power state controls amps */
871 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
872};
873
Matthew Ranostaye035b842007-11-06 11:53:55 +0100874static struct hda_verb stac92hd71bxx_core_init[] = {
875 /* set master volume and direct control */
876 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
877 /* connect headphone jack to dac1 */
878 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100879 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
880 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
881 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
882 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100883};
884
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400885#define HD_DISABLE_PORTF 2
Matthew Ranostay541eee82007-12-14 12:08:04 +0100886static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200887 /* start of config #1 */
888
889 /* connect port 0f to audio mixer */
890 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200891 /* unmute right and left channels for node 0x0f */
892 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
893 /* start of config #2 */
894
Matthew Ranostay541eee82007-12-14 12:08:04 +0100895 /* set master volume and direct control */
896 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
897 /* connect headphone jack to dac1 */
898 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200899 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100900 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
901 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100902 {}
903};
904
Tobin Davis8e21c342007-01-08 11:04:17 +0100905static struct hda_verb stac925x_core_init[] = {
906 /* set dac0mux for dac converter */
907 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
908 {}
909};
910
Mattc7d4b2f2005-06-27 14:59:41 +0200911static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200912 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200913 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200914 {}
915};
916
Tobin Davis93ed1502006-09-01 21:03:12 +0200917static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200918 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200919 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200920 /* unmute node 0x1b */
921 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
922 /* select node 0x03 as DAC */
923 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
924 {}
925};
926
Matt Porter3cc08dc2006-01-23 15:27:49 +0100927static struct hda_verb stac927x_core_init[] = {
928 /* set master volume and direct control */
929 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200930 /* enable analog pc beep path */
931 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100932 {}
933};
934
Matt Porterf3302a52006-07-31 12:49:34 +0200935static struct hda_verb stac9205_core_init[] = {
936 /* set master volume and direct control */
937 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200938 /* enable analog pc beep path */
939 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200940 {}
941};
942
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100943#define STAC_MONO_MUX \
944 { \
945 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
946 .name = "Mono Mux", \
947 .count = 1, \
948 .info = stac92xx_mono_mux_enum_info, \
949 .get = stac92xx_mono_mux_enum_get, \
950 .put = stac92xx_mono_mux_enum_put, \
951 }
952
Matthew Ranostay89385032008-09-11 09:49:39 -0400953#define STAC_AMP_MUX \
954 { \
955 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
956 .name = "Amp Selector Capture Switch", \
957 .count = 1, \
958 .info = stac92xx_amp_mux_enum_info, \
959 .get = stac92xx_amp_mux_enum_get, \
960 .put = stac92xx_amp_mux_enum_put, \
961 }
962
963#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
964 { \
965 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
966 .name = xname, \
967 .index = 0, \
968 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
969 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
970 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
971 .info = stac92xx_amp_volume_info, \
972 .get = stac92xx_amp_volume_get, \
973 .put = stac92xx_amp_volume_put, \
974 .tlv = { .c = snd_hda_mixer_amp_tlv }, \
975 .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
976 }
977
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200978#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200979 { \
980 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
981 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200982 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200983 .info = stac92xx_mux_enum_info, \
984 .get = stac92xx_mux_enum_get, \
985 .put = stac92xx_mux_enum_put, \
986 }
987
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100988#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200989 { \
990 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
991 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100992 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200993 .info = stac92xx_aloopback_info, \
994 .get = stac92xx_aloopback_get, \
995 .put = stac92xx_aloopback_put, \
996 .private_value = verb_read | (verb_write << 16), \
997 }
998
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100999static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +02001000 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
1001 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001002 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +02001003 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
1004 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +02001005 { } /* end */
1006};
1007
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001008#define DELL_M6_MIXER 6
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001009static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001010 /* start of config #1 */
1011 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1012 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1013
1014 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1015 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1016
1017 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1018 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1019
1020 /* start of config #2 */
1021 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1022 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1023
1024 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1025 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1026
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001027 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
1028
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001029 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1030 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1031
1032 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1033 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1034
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001035 { } /* end */
1036};
1037
1038static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001039 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1040
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001041 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1042 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1043
1044 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1045 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1046
1047 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1048 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1049
1050 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1051 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1052
1053 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1054 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1055
1056 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1057 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1058
1059 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1060 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1061 { } /* end */
1062};
1063
1064static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001065 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1066
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001067 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1068 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1069
1070 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1071 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1072
1073 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1074 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1075
1076 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1077 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1078
1079 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1080 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1081
1082 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1083 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1084
1085 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1086 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1087 { } /* end */
1088};
1089
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001090
1091static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
1092 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
1093 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
1094
1095 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
1096 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
1097
1098 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
1099 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
1100
1101 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
1102 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
1103
1104 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
1105 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
1106
1107 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
1108 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
1109
1110 /*
1111 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
1112 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
1113 */
1114 { } /* end */
1115};
1116
Matthew Ranostay541eee82007-12-14 12:08:04 +01001117static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001118 STAC_INPUT_SOURCE(2),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001119 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001120
Matthew Ranostay9b359472007-11-07 13:03:12 +01001121 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1122 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +01001123
1124 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1125 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001126 /* analog pc-beep replaced with digital beep support */
1127 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001128 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
1129 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001130 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001131
Matthew Ranostay687cb982008-10-11 13:52:43 -04001132 HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
1133 HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001134
Matthew Ranostay687cb982008-10-11 13:52:43 -04001135 HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
1136 HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001137
1138 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
1139 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
1140
1141 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
1142 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001143 { } /* end */
1144};
1145
Matthew Ranostay541eee82007-12-14 12:08:04 +01001146static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +01001147 STAC_INPUT_SOURCE(2),
1148 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
1149
Matthew Ranostay541eee82007-12-14 12:08:04 +01001150 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1151 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001152
1153 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1154 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001155 { } /* end */
1156};
1157
Tobin Davis8e21c342007-01-08 11:04:17 +01001158static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001159 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001160 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001161 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001162 { } /* end */
1163};
1164
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001165static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001166 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001167 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001168
1169 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1170 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001171
1172 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1173 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001174 { } /* end */
1175};
1176
1177/* This needs to be generated dynamically based on sequence */
1178static struct snd_kcontrol_new stac922x_mixer[] = {
1179 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001180 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1181 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001182
1183 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1184 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001185 { } /* end */
1186};
1187
1188
1189static struct snd_kcontrol_new stac927x_mixer[] = {
1190 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001191 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001192
1193 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1194 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001195
1196 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1197 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001198
1199 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1200 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001201 { } /* end */
1202};
1203
Takashi Iwai1697055e2007-12-18 18:05:52 +01001204static struct snd_kcontrol_new stac_dmux_mixer = {
1205 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1206 .name = "Digital Input Source",
1207 /* count set later */
1208 .info = stac92xx_dmux_enum_info,
1209 .get = stac92xx_dmux_enum_get,
1210 .put = stac92xx_dmux_enum_put,
1211};
1212
Matthew Ranostayd9737752008-09-07 12:03:41 +02001213static struct snd_kcontrol_new stac_smux_mixer = {
1214 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001215 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001216 /* count set later */
1217 .info = stac92xx_smux_enum_info,
1218 .get = stac92xx_smux_enum_get,
1219 .put = stac92xx_smux_enum_put,
1220};
1221
Takashi Iwai2134ea42008-01-10 16:53:55 +01001222static const char *slave_vols[] = {
1223 "Front Playback Volume",
1224 "Surround Playback Volume",
1225 "Center Playback Volume",
1226 "LFE Playback Volume",
1227 "Side Playback Volume",
1228 "Headphone Playback Volume",
1229 "Headphone Playback Volume",
1230 "Speaker Playback Volume",
1231 "External Speaker Playback Volume",
1232 "Speaker2 Playback Volume",
1233 NULL
1234};
1235
1236static const char *slave_sws[] = {
1237 "Front Playback Switch",
1238 "Surround Playback Switch",
1239 "Center Playback Switch",
1240 "LFE Playback Switch",
1241 "Side Playback Switch",
1242 "Headphone Playback Switch",
1243 "Headphone Playback Switch",
1244 "Speaker Playback Switch",
1245 "External Speaker Playback Switch",
1246 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001247 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001248 NULL
1249};
1250
Takashi Iwai603c4012008-07-30 15:01:44 +02001251static void stac92xx_free_kctls(struct hda_codec *codec);
Takashi Iwaie4973e12008-11-18 09:32:42 +01001252static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
Takashi Iwai603c4012008-07-30 15:01:44 +02001253
Matt2f2f4252005-04-13 14:45:30 +02001254static int stac92xx_build_controls(struct hda_codec *codec)
1255{
1256 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaie4973e12008-11-18 09:32:42 +01001257 struct auto_pin_cfg *cfg = &spec->autocfg;
1258 hda_nid_t nid;
Matt2f2f4252005-04-13 14:45:30 +02001259 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001260 int i;
Matt2f2f4252005-04-13 14:45:30 +02001261
1262 err = snd_hda_add_new_ctls(codec, spec->mixer);
1263 if (err < 0)
1264 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001265
1266 for (i = 0; i < spec->num_mixers; i++) {
1267 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1268 if (err < 0)
1269 return err;
1270 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001271 if (spec->num_dmuxes > 0) {
1272 stac_dmux_mixer.count = spec->num_dmuxes;
Takashi Iwaid13bd412008-07-30 15:01:45 +02001273 err = snd_hda_ctl_add(codec,
Takashi Iwai1697055e2007-12-18 18:05:52 +01001274 snd_ctl_new1(&stac_dmux_mixer, codec));
1275 if (err < 0)
1276 return err;
1277 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001278 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001279 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1280 struct hda_input_mux *smux = &spec->private_smux;
1281 /* check for mute support on SPDIF out */
1282 if (wcaps & AC_WCAP_OUT_AMP) {
1283 smux->items[smux->num_items].label = "Off";
1284 smux->items[smux->num_items].index = 0;
1285 smux->num_items++;
1286 spec->spdif_mute = 1;
1287 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001288 stac_smux_mixer.count = spec->num_smuxes;
1289 err = snd_ctl_add(codec->bus->card,
1290 snd_ctl_new1(&stac_smux_mixer, codec));
1291 if (err < 0)
1292 return err;
1293 }
Mattc7d4b2f2005-06-27 14:59:41 +02001294
Mattdabbed62005-06-14 10:19:34 +02001295 if (spec->multiout.dig_out_nid) {
1296 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1297 if (err < 0)
1298 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001299 err = snd_hda_create_spdif_share_sw(codec,
1300 &spec->multiout);
1301 if (err < 0)
1302 return err;
1303 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001304 }
Harvey Harrisonda74ae32008-10-21 20:28:04 -07001305 if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001306 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1307 if (err < 0)
1308 return err;
1309 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001310
1311 /* if we have no master control, let's create it */
1312 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001313 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001314 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001315 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001316 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001317 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001318 if (err < 0)
1319 return err;
1320 }
1321 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1322 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1323 NULL, slave_sws);
1324 if (err < 0)
1325 return err;
1326 }
1327
Takashi Iwai603c4012008-07-30 15:01:44 +02001328 stac92xx_free_kctls(codec); /* no longer needed */
Takashi Iwaie4973e12008-11-18 09:32:42 +01001329
1330 /* create jack input elements */
1331 if (spec->hp_detect) {
1332 for (i = 0; i < cfg->hp_outs; i++) {
1333 int type = SND_JACK_HEADPHONE;
1334 nid = cfg->hp_pins[i];
1335 /* jack detection */
1336 if (cfg->hp_outs == i)
1337 type |= SND_JACK_LINEOUT;
1338 err = stac92xx_add_jack(codec, nid, type);
1339 if (err < 0)
1340 return err;
1341 }
1342 }
1343 for (i = 0; i < cfg->line_outs; i++) {
1344 err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
1345 SND_JACK_LINEOUT);
1346 if (err < 0)
1347 return err;
1348 }
1349 for (i = 0; i < AUTO_PIN_LAST; i++) {
1350 nid = cfg->input_pins[i];
1351 if (nid) {
1352 err = stac92xx_add_jack(codec, nid,
1353 SND_JACK_MICROPHONE);
1354 if (err < 0)
1355 return err;
1356 }
1357 }
1358
Mattdabbed62005-06-14 10:19:34 +02001359 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001360}
1361
Matt Porter403d1942005-11-29 15:00:51 +01001362static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001363 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001364 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1365};
1366
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001367/*
1368 STAC 9200 pin configs for
1369 102801A8
1370 102801DE
1371 102801E8
1372*/
1373static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001374 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1375 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001376};
1377
1378/*
1379 STAC 9200 pin configs for
1380 102801C0
1381 102801C1
1382*/
1383static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001384 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1385 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001386};
1387
1388/*
1389 STAC 9200 pin configs for
1390 102801C4 (Dell Dimension E310)
1391 102801C5
1392 102801C7
1393 102801D9
1394 102801DA
1395 102801E3
1396*/
1397static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001398 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1399 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001400};
1401
1402
1403/*
1404 STAC 9200-32 pin configs for
1405 102801B5 (Dell Inspiron 630m)
1406 102801D8 (Dell Inspiron 640m)
1407*/
1408static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001409 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1410 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001411};
1412
1413/*
1414 STAC 9200-32 pin configs for
1415 102801C2 (Dell Latitude D620)
1416 102801C8
1417 102801CC (Dell Latitude D820)
1418 102801D4
1419 102801D6
1420*/
1421static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001422 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1423 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001424};
1425
1426/*
1427 STAC 9200-32 pin configs for
1428 102801CE (Dell XPS M1710)
1429 102801CF (Dell Precision M90)
1430*/
1431static unsigned int dell9200_m23_pin_configs[8] = {
1432 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1433 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1434};
1435
1436/*
1437 STAC 9200-32 pin configs for
1438 102801C9
1439 102801CA
1440 102801CB (Dell Latitude 120L)
1441 102801D3
1442*/
1443static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001444 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1445 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001446};
1447
1448/*
1449 STAC 9200-32 pin configs for
1450 102801BD (Dell Inspiron E1505n)
1451 102801EE
1452 102801EF
1453*/
1454static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001455 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1456 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001457};
1458
1459/*
1460 STAC 9200-32 pin configs for
1461 102801F5 (Dell Inspiron 1501)
1462 102801F6
1463*/
1464static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001465 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1466 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001467};
1468
1469/*
1470 STAC 9200-32
1471 102801CD (Dell Inspiron E1705/9400)
1472*/
1473static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001474 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1475 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001476};
1477
Tobin Davisbf277782008-02-03 20:31:47 +01001478static unsigned int oqo9200_pin_configs[8] = {
1479 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1480 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1481};
1482
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001483
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001484static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1485 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001486 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001487 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1488 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1489 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1490 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1491 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1492 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1493 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1494 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1495 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1496 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001497 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001498};
1499
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001500static const char *stac9200_models[STAC_9200_MODELS] = {
1501 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001502 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001503 [STAC_9200_DELL_D21] = "dell-d21",
1504 [STAC_9200_DELL_D22] = "dell-d22",
1505 [STAC_9200_DELL_D23] = "dell-d23",
1506 [STAC_9200_DELL_M21] = "dell-m21",
1507 [STAC_9200_DELL_M22] = "dell-m22",
1508 [STAC_9200_DELL_M23] = "dell-m23",
1509 [STAC_9200_DELL_M24] = "dell-m24",
1510 [STAC_9200_DELL_M25] = "dell-m25",
1511 [STAC_9200_DELL_M26] = "dell-m26",
1512 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001513 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001514 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001515};
1516
1517static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1518 /* SigmaTel reference board */
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1520 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001521 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001522 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1523 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001524 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001525 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1527 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1529 "unknown Dell", STAC_9200_DELL_D22),
1530 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1531 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001532 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001533 "Dell Latitude D620", STAC_9200_DELL_M22),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1535 "unknown Dell", STAC_9200_DELL_D23),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1537 "unknown Dell", STAC_9200_DELL_D23),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1539 "unknown Dell", STAC_9200_DELL_M22),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1541 "unknown Dell", STAC_9200_DELL_M24),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1543 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001545 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001546 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001547 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001548 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001549 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001550 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001551 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001552 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001553 "Dell Precision M90", STAC_9200_DELL_M23),
1554 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1555 "unknown Dell", STAC_9200_DELL_M22),
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1557 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001558 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001559 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001560 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001561 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1563 "unknown Dell", STAC_9200_DELL_D23),
1564 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1565 "unknown Dell", STAC_9200_DELL_D23),
1566 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1567 "unknown Dell", STAC_9200_DELL_D21),
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1569 "unknown Dell", STAC_9200_DELL_D23),
1570 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1571 "unknown Dell", STAC_9200_DELL_D21),
1572 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1573 "unknown Dell", STAC_9200_DELL_M25),
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1575 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001576 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001577 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1578 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1579 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001580 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001581 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001582 /* Gateway machines needs EAPD to be set on resume */
1583 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1584 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1585 STAC_9200_GATEWAY),
1586 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1587 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001588 /* OQO Mobile */
1589 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001590 {} /* terminator */
1591};
1592
Tobin Davis8e21c342007-01-08 11:04:17 +01001593static unsigned int ref925x_pin_configs[8] = {
1594 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001595 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001596};
1597
1598static unsigned int stac925x_MA6_pin_configs[8] = {
1599 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1600 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1601};
1602
Tobin Davis2c11f952007-05-17 09:36:34 +02001603static unsigned int stac925x_PA6_pin_configs[8] = {
1604 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1605 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1606};
1607
Tobin Davis8e21c342007-01-08 11:04:17 +01001608static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001609 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1610 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001611};
1612
1613static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1614 [STAC_REF] = ref925x_pin_configs,
1615 [STAC_M2_2] = stac925xM2_2_pin_configs,
1616 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001617 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001618};
1619
1620static const char *stac925x_models[STAC_925x_MODELS] = {
1621 [STAC_REF] = "ref",
1622 [STAC_M2_2] = "m2-2",
1623 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001624 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001625};
1626
1627static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1628 /* SigmaTel reference board */
1629 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001630 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001631 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1632 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1633 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001634 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001635 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1636 {} /* terminator */
1637};
1638
Matthew Ranostaya7662642008-02-21 07:51:14 +01001639static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001640 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1641 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1642 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001643 0x01452050,
1644};
1645
1646static unsigned int dell_m6_pin_configs[13] = {
1647 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001648 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001649 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1650 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001651};
1652
1653static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001654 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1655 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001656 [STAC_DELL_EQ] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001657};
1658
1659static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1660 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001661 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001662 [STAC_DELL_EQ] = "dell-eq",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001663};
1664
1665static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1666 /* SigmaTel reference board */
1667 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001668 "DFI LanParty", STAC_92HD73XX_REF),
1669 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1670 "unknown Dell", STAC_DELL_M6),
1671 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1672 "unknown Dell", STAC_DELL_M6),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1674 "unknown Dell", STAC_DELL_M6),
1675 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1676 "unknown Dell", STAC_DELL_M6),
1677 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1678 "unknown Dell", STAC_DELL_M6),
1679 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1680 "unknown Dell", STAC_DELL_M6),
1681 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1682 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001683 {} /* terminator */
1684};
1685
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001686static unsigned int ref92hd83xxx_pin_configs[14] = {
1687 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1688 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1689 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1690 0x01451160, 0x98560170,
1691};
1692
1693static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1694 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1695};
1696
1697static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1698 [STAC_92HD83XXX_REF] = "ref",
1699};
1700
1701static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1702 /* SigmaTel reference board */
1703 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1704 "DFI LanParty", STAC_92HD71BXX_REF),
1705};
1706
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001707static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001708 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001709 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001710 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001711};
1712
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001713static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001714 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001715 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001716 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001717};
1718
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001719static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001720 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1721 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001722 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001723};
1724
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001725static unsigned int dell_m4_3_pin_configs[11] = {
1726 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1727 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
1728 0x40f000f0, 0x044413b0, 0x044413b0,
1729};
1730
Matthew Ranostaye035b842007-11-06 11:53:55 +01001731static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1732 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001733 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1734 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001735 [STAC_DELL_M4_3] = dell_m4_3_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001736 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001737};
1738
1739static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1740 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001741 [STAC_DELL_M4_1] = "dell-m4-1",
1742 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001743 [STAC_DELL_M4_3] = "dell-m4-3",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001744 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001745};
1746
1747static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1748 /* SigmaTel reference board */
1749 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1750 "DFI LanParty", STAC_92HD71BXX_REF),
Takashi Iwai80bf2722008-11-18 10:48:41 +01001751 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
1752 "HP dv5", STAC_HP_M4),
1753 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
1754 "HP dv7", STAC_HP_M4),
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04001755 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
1756 "unknown HP", STAC_HP_M4),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001757 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1758 "unknown Dell", STAC_DELL_M4_1),
1759 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1760 "unknown Dell", STAC_DELL_M4_1),
1761 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1762 "unknown Dell", STAC_DELL_M4_1),
1763 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1764 "unknown Dell", STAC_DELL_M4_1),
1765 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1766 "unknown Dell", STAC_DELL_M4_1),
1767 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1768 "unknown Dell", STAC_DELL_M4_1),
1769 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1770 "unknown Dell", STAC_DELL_M4_1),
1771 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1772 "unknown Dell", STAC_DELL_M4_2),
1773 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1774 "unknown Dell", STAC_DELL_M4_2),
1775 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1776 "unknown Dell", STAC_DELL_M4_2),
1777 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1778 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001779 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa,
1780 "unknown Dell", STAC_DELL_M4_3),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001781 {} /* terminator */
1782};
1783
Matt Porter403d1942005-11-29 15:00:51 +01001784static unsigned int ref922x_pin_configs[10] = {
1785 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1786 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001787 0x40000100, 0x40000100,
1788};
1789
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001790/*
1791 STAC 922X pin configs for
1792 102801A7
1793 102801AB
1794 102801A9
1795 102801D1
1796 102801D2
1797*/
1798static unsigned int dell_922x_d81_pin_configs[10] = {
1799 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1800 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1801 0x01813122, 0x400001f2,
1802};
1803
1804/*
1805 STAC 922X pin configs for
1806 102801AC
1807 102801D0
1808*/
1809static unsigned int dell_922x_d82_pin_configs[10] = {
1810 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1811 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1812 0x01813122, 0x400001f1,
1813};
1814
1815/*
1816 STAC 922X pin configs for
1817 102801BF
1818*/
1819static unsigned int dell_922x_m81_pin_configs[10] = {
1820 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1821 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1822 0x40C003f1, 0x405003f0,
1823};
1824
1825/*
1826 STAC 9221 A1 pin configs for
1827 102801D7 (Dell XPS M1210)
1828*/
1829static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001830 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1831 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001832 0x508003f3, 0x405003f4,
1833};
1834
Matt Porter403d1942005-11-29 15:00:51 +01001835static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001836 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001837 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1838 0x02a19120, 0x40000100,
1839};
1840
1841static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001842 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1843 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001844 0x02a19320, 0x40000100,
1845};
1846
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001847static unsigned int intel_mac_v1_pin_configs[10] = {
1848 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1849 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001850 0x400000fc, 0x400000fb,
1851};
1852
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001853static unsigned int intel_mac_v2_pin_configs[10] = {
1854 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1855 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001856 0x400000fc, 0x400000fb,
1857};
1858
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001859static unsigned int intel_mac_v3_pin_configs[10] = {
1860 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1861 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1862 0x400000fc, 0x400000fb,
1863};
1864
1865static unsigned int intel_mac_v4_pin_configs[10] = {
1866 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1867 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1868 0x400000fc, 0x400000fb,
1869};
1870
1871static unsigned int intel_mac_v5_pin_configs[10] = {
1872 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1873 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1874 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001875};
1876
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001877static unsigned int ecs202_pin_configs[10] = {
1878 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1879 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1880 0x9037012e, 0x40e000f2,
1881};
Takashi Iwai76c08822007-06-19 12:17:42 +02001882
Takashi Iwai19039bd2006-06-28 15:52:16 +02001883static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001884 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001885 [STAC_D945GTP3] = d945gtp3_pin_configs,
1886 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001887 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1888 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1889 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1890 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1891 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001892 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001893 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001894 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1895 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1896 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1897 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1898 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1899 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001900 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001901 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1902 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1903 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1904 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001905};
1906
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001907static const char *stac922x_models[STAC_922X_MODELS] = {
1908 [STAC_D945_REF] = "ref",
1909 [STAC_D945GTP5] = "5stack",
1910 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001911 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1912 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1913 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1914 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1915 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001916 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001917 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001918 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001919 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001920 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1921 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001922 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001923 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001924 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001925 [STAC_922X_DELL_D81] = "dell-d81",
1926 [STAC_922X_DELL_D82] = "dell-d82",
1927 [STAC_922X_DELL_M81] = "dell-m81",
1928 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001929};
1930
1931static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1932 /* SigmaTel reference board */
1933 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1934 "DFI LanParty", STAC_D945_REF),
1935 /* Intel 945G based systems */
1936 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1937 "Intel D945G", STAC_D945GTP3),
1938 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1939 "Intel D945G", STAC_D945GTP3),
1940 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1941 "Intel D945G", STAC_D945GTP3),
1942 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1943 "Intel D945G", STAC_D945GTP3),
1944 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1945 "Intel D945G", STAC_D945GTP3),
1946 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1947 "Intel D945G", STAC_D945GTP3),
1948 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1949 "Intel D945G", STAC_D945GTP3),
1950 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1951 "Intel D945G", STAC_D945GTP3),
1952 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1953 "Intel D945G", STAC_D945GTP3),
1954 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1955 "Intel D945G", STAC_D945GTP3),
1956 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1957 "Intel D945G", STAC_D945GTP3),
1958 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1959 "Intel D945G", STAC_D945GTP3),
1960 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1961 "Intel D945G", STAC_D945GTP3),
1962 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1963 "Intel D945G", STAC_D945GTP3),
1964 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1965 "Intel D945G", STAC_D945GTP3),
1966 /* Intel D945G 5-stack systems */
1967 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1968 "Intel D945G", STAC_D945GTP5),
1969 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1970 "Intel D945G", STAC_D945GTP5),
1971 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1972 "Intel D945G", STAC_D945GTP5),
1973 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1974 "Intel D945G", STAC_D945GTP5),
1975 /* Intel 945P based systems */
1976 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1977 "Intel D945P", STAC_D945GTP3),
1978 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1979 "Intel D945P", STAC_D945GTP3),
1980 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1981 "Intel D945P", STAC_D945GTP3),
1982 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1983 "Intel D945P", STAC_D945GTP3),
1984 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1985 "Intel D945P", STAC_D945GTP3),
1986 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1987 "Intel D945P", STAC_D945GTP5),
1988 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001989 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001990 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001991 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001992 /* Dell systems */
1993 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1994 "unknown Dell", STAC_922X_DELL_D81),
1995 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1996 "unknown Dell", STAC_922X_DELL_D81),
1997 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1998 "unknown Dell", STAC_922X_DELL_D81),
1999 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
2000 "unknown Dell", STAC_922X_DELL_D82),
2001 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
2002 "unknown Dell", STAC_922X_DELL_M81),
2003 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
2004 "unknown Dell", STAC_922X_DELL_D82),
2005 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
2006 "unknown Dell", STAC_922X_DELL_D81),
2007 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
2008 "unknown Dell", STAC_922X_DELL_D81),
2009 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
2010 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03002011 /* ECS/PC Chips boards */
2012 SND_PCI_QUIRK(0x1019, 0x2144,
2013 "ECS/PC chips", STAC_ECS_202),
2014 SND_PCI_QUIRK(0x1019, 0x2608,
2015 "ECS/PC chips", STAC_ECS_202),
2016 SND_PCI_QUIRK(0x1019, 0x2633,
2017 "ECS/PC chips P17G/1333", STAC_ECS_202),
2018 SND_PCI_QUIRK(0x1019, 0x2811,
2019 "ECS/PC chips", STAC_ECS_202),
2020 SND_PCI_QUIRK(0x1019, 0x2812,
2021 "ECS/PC chips", STAC_ECS_202),
2022 SND_PCI_QUIRK(0x1019, 0x2813,
2023 "ECS/PC chips", STAC_ECS_202),
2024 SND_PCI_QUIRK(0x1019, 0x2814,
2025 "ECS/PC chips", STAC_ECS_202),
2026 SND_PCI_QUIRK(0x1019, 0x2815,
2027 "ECS/PC chips", STAC_ECS_202),
2028 SND_PCI_QUIRK(0x1019, 0x2816,
2029 "ECS/PC chips", STAC_ECS_202),
2030 SND_PCI_QUIRK(0x1019, 0x2817,
2031 "ECS/PC chips", STAC_ECS_202),
2032 SND_PCI_QUIRK(0x1019, 0x2818,
2033 "ECS/PC chips", STAC_ECS_202),
2034 SND_PCI_QUIRK(0x1019, 0x2819,
2035 "ECS/PC chips", STAC_ECS_202),
2036 SND_PCI_QUIRK(0x1019, 0x2820,
2037 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01002038 {} /* terminator */
2039};
2040
Matt Porter3cc08dc2006-01-23 15:27:49 +01002041static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02002042 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2043 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
2044 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
2045 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002046};
2047
Tobin Davis93ed1502006-09-01 21:03:12 +02002048static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002049 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
2050 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
2051 0x40000100, 0x40000100, 0x40000100, 0x40000100,
2052 0x40000100, 0x40000100
2053};
2054
Tobin Davis93ed1502006-09-01 21:03:12 +02002055static unsigned int d965_5st_pin_configs[14] = {
2056 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2057 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
2058 0x40000100, 0x40000100, 0x40000100, 0x01442070,
2059 0x40000100, 0x40000100
2060};
2061
Tobin Davis4ff076e2007-08-07 11:48:12 +02002062static unsigned int dell_3st_pin_configs[14] = {
2063 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
2064 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002065 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02002066 0x40c003fc, 0x40000100
2067};
2068
Tobin Davis93ed1502006-09-01 21:03:12 +02002069static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002070 [STAC_D965_REF] = ref927x_pin_configs,
2071 [STAC_D965_3ST] = d965_3st_pin_configs,
2072 [STAC_D965_5ST] = d965_5st_pin_configs,
2073 [STAC_DELL_3ST] = dell_3st_pin_configs,
2074 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002075};
2076
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002077static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002078 [STAC_D965_REF] = "ref",
2079 [STAC_D965_3ST] = "3stack",
2080 [STAC_D965_5ST] = "5stack",
2081 [STAC_DELL_3ST] = "dell-3stack",
2082 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002083};
2084
2085static struct snd_pci_quirk stac927x_cfg_tbl[] = {
2086 /* SigmaTel reference board */
2087 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2088 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002089 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002090 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2091 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002092 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002093 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
2094 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
2095 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
2096 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
2097 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
2098 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
2099 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
2100 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
2101 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
2102 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
2103 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
2104 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
2105 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
2106 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
2107 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
2108 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002109 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002110 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002111 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002112 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2113 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002114 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002115 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
2116 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002117 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02002118 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002119 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2120 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2121 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2122 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002123 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002124 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
2125 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
2126 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
2127 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
2128 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
2129 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
2130 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
2131 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
2132 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002133 {} /* terminator */
2134};
2135
Matt Porterf3302a52006-07-31 12:49:34 +02002136static unsigned int ref9205_pin_configs[12] = {
2137 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002138 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02002139 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02002140};
2141
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002142/*
2143 STAC 9205 pin configs for
2144 102801F1
2145 102801F2
2146 102801FC
2147 102801FD
2148 10280204
2149 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002150 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002151*/
2152static unsigned int dell_9205_m42_pin_configs[12] = {
2153 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
2154 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
2155 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
2156};
2157
2158/*
2159 STAC 9205 pin configs for
2160 102801F9
2161 102801FA
2162 102801FE
2163 102801FF (Dell Precision M4300)
2164 10280206
2165 10280200
2166 10280201
2167*/
2168static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002169 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
2170 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
2171 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
2172};
2173
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002174static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002175 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
2176 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
2177 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
2178};
2179
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002180static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002181 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002182 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
2183 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
2184 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02002185};
2186
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002187static const char *stac9205_models[STAC_9205_MODELS] = {
2188 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002189 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002190 [STAC_9205_DELL_M43] = "dell-m43",
2191 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002192};
2193
2194static struct snd_pci_quirk stac9205_cfg_tbl[] = {
2195 /* SigmaTel reference board */
2196 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2197 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002198 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2199 "unknown Dell", STAC_9205_DELL_M42),
2200 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2201 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002202 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002203 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002204 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2205 "Dell Precision", STAC_9205_DELL_M43),
2206 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2207 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002208 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2209 "unknown Dell", STAC_9205_DELL_M42),
2210 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2211 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002212 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2213 "Dell Precision", STAC_9205_DELL_M43),
2214 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002215 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002216 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2217 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002218 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2219 "Dell Precision", STAC_9205_DELL_M43),
2220 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2221 "Dell Precision", STAC_9205_DELL_M43),
2222 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2223 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002224 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2225 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002226 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2227 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002228 {} /* terminator */
2229};
2230
Richard Fish11b44bb2006-08-23 18:31:34 +02002231static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2232{
2233 int i;
2234 struct sigmatel_spec *spec = codec->spec;
2235
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002236 kfree(spec->pin_configs);
2237 spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs),
2238 GFP_KERNEL);
2239 if (!spec->pin_configs)
2240 return -ENOMEM;
Richard Fish11b44bb2006-08-23 18:31:34 +02002241
2242 for (i = 0; i < spec->num_pins; i++) {
2243 hda_nid_t nid = spec->pin_nids[i];
2244 unsigned int pin_cfg;
2245
2246 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2247 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2248 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2249 nid, pin_cfg);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002250 spec->pin_configs[i] = pin_cfg;
Richard Fish11b44bb2006-08-23 18:31:34 +02002251 }
2252
2253 return 0;
2254}
2255
Matthew Ranostay87d48362007-07-17 11:52:24 +02002256static void stac92xx_set_config_reg(struct hda_codec *codec,
2257 hda_nid_t pin_nid, unsigned int pin_config)
2258{
2259 int i;
2260 snd_hda_codec_write(codec, pin_nid, 0,
2261 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2262 pin_config & 0x000000ff);
2263 snd_hda_codec_write(codec, pin_nid, 0,
2264 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2265 (pin_config & 0x0000ff00) >> 8);
2266 snd_hda_codec_write(codec, pin_nid, 0,
2267 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2268 (pin_config & 0x00ff0000) >> 16);
2269 snd_hda_codec_write(codec, pin_nid, 0,
2270 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2271 pin_config >> 24);
2272 i = snd_hda_codec_read(codec, pin_nid, 0,
2273 AC_VERB_GET_CONFIG_DEFAULT,
2274 0x00);
2275 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2276 pin_nid, i);
2277}
2278
Matt2f2f4252005-04-13 14:45:30 +02002279static void stac92xx_set_config_regs(struct hda_codec *codec)
2280{
2281 int i;
2282 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002283
Matthew Ranostay87d48362007-07-17 11:52:24 +02002284 if (!spec->pin_configs)
2285 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002286
Matthew Ranostay87d48362007-07-17 11:52:24 +02002287 for (i = 0; i < spec->num_pins; i++)
2288 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2289 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002290}
Matt2f2f4252005-04-13 14:45:30 +02002291
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002292static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins)
2293{
2294 struct sigmatel_spec *spec = codec->spec;
2295
2296 if (!pins)
2297 return stac92xx_save_bios_config_regs(codec);
2298
2299 kfree(spec->pin_configs);
2300 spec->pin_configs = kmemdup(pins,
2301 spec->num_pins * sizeof(*pins),
2302 GFP_KERNEL);
2303 if (!spec->pin_configs)
2304 return -ENOMEM;
2305
2306 stac92xx_set_config_regs(codec);
2307 return 0;
2308}
2309
2310static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid,
2311 unsigned int cfg)
2312{
2313 struct sigmatel_spec *spec = codec->spec;
2314 int i;
2315
2316 for (i = 0; i < spec->num_pins; i++) {
2317 if (spec->pin_nids[i] == nid) {
2318 spec->pin_configs[i] = cfg;
2319 stac92xx_set_config_reg(codec, nid, cfg);
2320 break;
2321 }
2322 }
2323}
2324
Matt2f2f4252005-04-13 14:45:30 +02002325/*
2326 * Analog playback callbacks
2327 */
2328static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2329 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002330 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002331{
2332 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002333 if (spec->stream_delay)
2334 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002335 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2336 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002337}
2338
2339static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2340 struct hda_codec *codec,
2341 unsigned int stream_tag,
2342 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002343 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002344{
2345 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002346 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002347}
2348
2349static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2350 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002351 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002352{
2353 struct sigmatel_spec *spec = codec->spec;
2354 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2355}
2356
2357/*
Mattdabbed62005-06-14 10:19:34 +02002358 * Digital playback callbacks
2359 */
2360static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2361 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002362 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002363{
2364 struct sigmatel_spec *spec = codec->spec;
2365 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2366}
2367
2368static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2369 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002370 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002371{
2372 struct sigmatel_spec *spec = codec->spec;
2373 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2374}
2375
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002376static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2377 struct hda_codec *codec,
2378 unsigned int stream_tag,
2379 unsigned int format,
2380 struct snd_pcm_substream *substream)
2381{
2382 struct sigmatel_spec *spec = codec->spec;
2383 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2384 stream_tag, format, substream);
2385}
2386
Mattdabbed62005-06-14 10:19:34 +02002387
2388/*
Matt2f2f4252005-04-13 14:45:30 +02002389 * Analog capture callbacks
2390 */
2391static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2392 struct hda_codec *codec,
2393 unsigned int stream_tag,
2394 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002395 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002396{
2397 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002398 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002399
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002400 if (spec->powerdown_adcs) {
2401 msleep(40);
2402 snd_hda_codec_write_cache(codec, nid, 0,
2403 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2404 }
2405 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002406 return 0;
2407}
2408
2409static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2410 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002411 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002412{
2413 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002414 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002415
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002416 snd_hda_codec_cleanup_stream(codec, nid);
2417 if (spec->powerdown_adcs)
2418 snd_hda_codec_write_cache(codec, nid, 0,
2419 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002420 return 0;
2421}
2422
Mattdabbed62005-06-14 10:19:34 +02002423static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2424 .substreams = 1,
2425 .channels_min = 2,
2426 .channels_max = 2,
2427 /* NID is set in stac92xx_build_pcms */
2428 .ops = {
2429 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002430 .close = stac92xx_dig_playback_pcm_close,
2431 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002432 },
2433};
2434
2435static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2436 .substreams = 1,
2437 .channels_min = 2,
2438 .channels_max = 2,
2439 /* NID is set in stac92xx_build_pcms */
2440};
2441
Matt2f2f4252005-04-13 14:45:30 +02002442static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2443 .substreams = 1,
2444 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002445 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002446 .nid = 0x02, /* NID to query formats and rates */
2447 .ops = {
2448 .open = stac92xx_playback_pcm_open,
2449 .prepare = stac92xx_playback_pcm_prepare,
2450 .cleanup = stac92xx_playback_pcm_cleanup
2451 },
2452};
2453
Matt Porter3cc08dc2006-01-23 15:27:49 +01002454static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2455 .substreams = 1,
2456 .channels_min = 2,
2457 .channels_max = 2,
2458 .nid = 0x06, /* NID to query formats and rates */
2459 .ops = {
2460 .open = stac92xx_playback_pcm_open,
2461 .prepare = stac92xx_playback_pcm_prepare,
2462 .cleanup = stac92xx_playback_pcm_cleanup
2463 },
2464};
2465
Matt2f2f4252005-04-13 14:45:30 +02002466static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002467 .channels_min = 2,
2468 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002469 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002470 .ops = {
2471 .prepare = stac92xx_capture_pcm_prepare,
2472 .cleanup = stac92xx_capture_pcm_cleanup
2473 },
2474};
2475
2476static int stac92xx_build_pcms(struct hda_codec *codec)
2477{
2478 struct sigmatel_spec *spec = codec->spec;
2479 struct hda_pcm *info = spec->pcm_rec;
2480
2481 codec->num_pcms = 1;
2482 codec->pcm_info = info;
2483
Mattc7d4b2f2005-06-27 14:59:41 +02002484 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002485 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002486 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002487 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002488 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002489
2490 if (spec->alt_switch) {
2491 codec->num_pcms++;
2492 info++;
2493 info->name = "STAC92xx Analog Alt";
2494 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2495 }
Matt2f2f4252005-04-13 14:45:30 +02002496
Mattdabbed62005-06-14 10:19:34 +02002497 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2498 codec->num_pcms++;
2499 info++;
2500 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002501 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002502 if (spec->multiout.dig_out_nid) {
2503 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2504 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2505 }
2506 if (spec->dig_in_nid) {
2507 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2508 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2509 }
2510 }
2511
Matt2f2f4252005-04-13 14:45:30 +02002512 return 0;
2513}
2514
Takashi Iwaic960a032006-03-23 17:06:28 +01002515static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2516{
2517 unsigned int pincap = snd_hda_param_read(codec, nid,
2518 AC_PAR_PIN_CAP);
2519 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2520 if (pincap & AC_PINCAP_VREF_100)
2521 return AC_PINCTL_VREF_100;
2522 if (pincap & AC_PINCAP_VREF_80)
2523 return AC_PINCTL_VREF_80;
2524 if (pincap & AC_PINCAP_VREF_50)
2525 return AC_PINCTL_VREF_50;
2526 if (pincap & AC_PINCAP_VREF_GRD)
2527 return AC_PINCTL_VREF_GRD;
2528 return 0;
2529}
2530
Matt Porter403d1942005-11-29 15:00:51 +01002531static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2532
2533{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002534 snd_hda_codec_write_cache(codec, nid, 0,
2535 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002536}
2537
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002538#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2539
2540static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2541 struct snd_ctl_elem_value *ucontrol)
2542{
2543 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2544 struct sigmatel_spec *spec = codec->spec;
2545
Takashi Iwaid7a89432008-11-12 09:48:04 +01002546 ucontrol->value.integer.value[0] = !!spec->hp_switch;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002547 return 0;
2548}
2549
2550static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2551 struct snd_ctl_elem_value *ucontrol)
2552{
2553 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2554 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaid7a89432008-11-12 09:48:04 +01002555 int nid = kcontrol->private_value;
2556
2557 spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002558
2559 /* check to be sure that the ports are upto date with
2560 * switch changes
2561 */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002562 codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002563
2564 return 1;
2565}
2566
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002567#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002568
2569static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2570{
2571 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2572 struct sigmatel_spec *spec = codec->spec;
2573 int io_idx = kcontrol-> private_value & 0xff;
2574
2575 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2576 return 0;
2577}
2578
2579static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2580{
2581 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2582 struct sigmatel_spec *spec = codec->spec;
2583 hda_nid_t nid = kcontrol->private_value >> 8;
2584 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002585 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002586
2587 spec->io_switch[io_idx] = val;
2588
2589 if (val)
2590 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002591 else {
2592 unsigned int pinctl = AC_PINCTL_IN_EN;
2593 if (io_idx) /* set VREF for mic */
2594 pinctl |= stac92xx_get_vref(codec, nid);
2595 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2596 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002597
2598 /* check the auto-mute again: we need to mute/unmute the speaker
2599 * appropriately according to the pin direction
2600 */
2601 if (spec->hp_detect)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002602 codec->patch_ops.unsol_event(codec,
2603 (STAC_HP_EVENT | nid) << 26);
Jiang Zhe40c1d302007-11-12 13:05:16 +01002604
Matt Porter403d1942005-11-29 15:00:51 +01002605 return 1;
2606}
2607
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002608#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2609
2610static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2611 struct snd_ctl_elem_value *ucontrol)
2612{
2613 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2614 struct sigmatel_spec *spec = codec->spec;
2615
2616 ucontrol->value.integer.value[0] = spec->clfe_swap;
2617 return 0;
2618}
2619
2620static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2621 struct snd_ctl_elem_value *ucontrol)
2622{
2623 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2624 struct sigmatel_spec *spec = codec->spec;
2625 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002626 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002627
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002628 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002629 return 0;
2630
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002631 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002632
2633 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2634 spec->clfe_swap ? 0x4 : 0x0);
2635
2636 return 1;
2637}
2638
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002639#define STAC_CODEC_HP_SWITCH(xname) \
2640 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2641 .name = xname, \
2642 .index = 0, \
2643 .info = stac92xx_hp_switch_info, \
2644 .get = stac92xx_hp_switch_get, \
2645 .put = stac92xx_hp_switch_put, \
2646 }
2647
Matt Porter403d1942005-11-29 15:00:51 +01002648#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2649 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2650 .name = xname, \
2651 .index = 0, \
2652 .info = stac92xx_io_switch_info, \
2653 .get = stac92xx_io_switch_get, \
2654 .put = stac92xx_io_switch_put, \
2655 .private_value = xpval, \
2656 }
2657
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002658#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2659 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2660 .name = xname, \
2661 .index = 0, \
2662 .info = stac92xx_clfe_switch_info, \
2663 .get = stac92xx_clfe_switch_get, \
2664 .put = stac92xx_clfe_switch_put, \
2665 .private_value = xpval, \
2666 }
Matt Porter403d1942005-11-29 15:00:51 +01002667
Mattc7d4b2f2005-06-27 14:59:41 +02002668enum {
2669 STAC_CTL_WIDGET_VOL,
2670 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002671 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002672 STAC_CTL_WIDGET_AMP_MUX,
2673 STAC_CTL_WIDGET_AMP_VOL,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002674 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002675 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002676 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002677};
2678
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002679static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002680 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2681 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002682 STAC_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002683 STAC_AMP_MUX,
2684 STAC_AMP_VOL(NULL, 0, 0, 0, 0),
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002685 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002686 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002687 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002688};
2689
2690/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002691static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
2692 struct snd_kcontrol_new *ktemp,
2693 int idx, const char *name,
2694 unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002695{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002696 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002697
Takashi Iwai603c4012008-07-30 15:01:44 +02002698 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2699 knew = snd_array_new(&spec->kctls);
2700 if (!knew)
2701 return -ENOMEM;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002702 *knew = *ktemp;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002703 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002704 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002705 if (!knew->name)
Mattc7d4b2f2005-06-27 14:59:41 +02002706 return -ENOMEM;
2707 knew->private_value = val;
Mattc7d4b2f2005-06-27 14:59:41 +02002708 return 0;
2709}
2710
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002711static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
2712 int type, int idx, const char *name,
2713 unsigned long val)
2714{
2715 return stac92xx_add_control_temp(spec,
2716 &stac92xx_control_templates[type],
2717 idx, name, val);
2718}
2719
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002720
2721/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002722static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2723 const char *name, unsigned long val)
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002724{
2725 return stac92xx_add_control_idx(spec, type, 0, name, val);
2726}
2727
Matt Porter403d1942005-11-29 15:00:51 +01002728/* flag inputs as additional dynamic lineouts */
2729static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2730{
2731 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002732 unsigned int wcaps, wtype;
2733 int i, num_dacs = 0;
2734
2735 /* use the wcaps cache to count all DACs available for line-outs */
2736 for (i = 0; i < codec->num_nodes; i++) {
2737 wcaps = codec->wcaps[i];
2738 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002739
Steve Longerbeam7b043892007-05-03 20:50:03 +02002740 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2741 num_dacs++;
2742 }
Matt Porter403d1942005-11-29 15:00:51 +01002743
Steve Longerbeam7b043892007-05-03 20:50:03 +02002744 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2745
Matt Porter403d1942005-11-29 15:00:51 +01002746 switch (cfg->line_outs) {
2747 case 3:
2748 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002749 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002750 cfg->line_out_pins[cfg->line_outs] =
2751 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002752 spec->line_switch = 1;
2753 cfg->line_outs++;
2754 }
2755 break;
2756 case 2:
2757 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002758 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002759 cfg->line_out_pins[cfg->line_outs] =
2760 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002761 spec->line_switch = 1;
2762 cfg->line_outs++;
2763 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002764 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002765 cfg->line_out_pins[cfg->line_outs] =
2766 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002767 spec->mic_switch = 1;
2768 cfg->line_outs++;
2769 }
2770 break;
2771 case 1:
2772 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002773 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002774 cfg->line_out_pins[cfg->line_outs] =
2775 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002776 spec->line_switch = 1;
2777 cfg->line_outs++;
2778 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002779 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002780 cfg->line_out_pins[cfg->line_outs] =
2781 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002782 spec->mic_switch = 1;
2783 cfg->line_outs++;
2784 }
2785 break;
2786 }
2787
2788 return 0;
2789}
2790
Steve Longerbeam7b043892007-05-03 20:50:03 +02002791
2792static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2793{
2794 int i;
2795
2796 for (i = 0; i < spec->multiout.num_dacs; i++) {
2797 if (spec->multiout.dac_nids[i] == nid)
2798 return 1;
2799 }
2800
2801 return 0;
2802}
2803
Matt Porter3cc08dc2006-01-23 15:27:49 +01002804/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002805 * Fill in the dac_nids table from the parsed pin configuration
2806 * This function only works when every pin in line_out_pins[]
2807 * contains atleast one DAC in its connection list. Some 92xx
2808 * codecs are not connected directly to a DAC, such as the 9200
2809 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002810 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002811static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002812 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002813{
2814 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002815 int i, j, conn_len = 0;
2816 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2817 unsigned int wcaps, wtype;
2818
Mattc7d4b2f2005-06-27 14:59:41 +02002819 for (i = 0; i < cfg->line_outs; i++) {
2820 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002821 conn_len = snd_hda_get_connections(codec, nid, conn,
2822 HDA_MAX_CONNECTIONS);
2823 for (j = 0; j < conn_len; j++) {
2824 wcaps = snd_hda_param_read(codec, conn[j],
2825 AC_PAR_AUDIO_WIDGET_CAP);
2826 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002827 if (wtype != AC_WID_AUD_OUT ||
2828 (wcaps & AC_WCAP_DIGITAL))
2829 continue;
2830 /* conn[j] is a DAC routed to this line-out */
2831 if (!is_in_dac_nids(spec, conn[j]))
2832 break;
2833 }
2834
2835 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002836 if (spec->multiout.num_dacs > 0) {
2837 /* we have already working output pins,
2838 * so let's drop the broken ones again
2839 */
2840 cfg->line_outs = spec->multiout.num_dacs;
2841 break;
2842 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002843 /* error out, no available DAC found */
2844 snd_printk(KERN_ERR
2845 "%s: No available DAC for pin 0x%x\n",
2846 __func__, nid);
2847 return -ENODEV;
2848 }
2849
2850 spec->multiout.dac_nids[i] = conn[j];
2851 spec->multiout.num_dacs++;
2852 if (conn_len > 1) {
2853 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002854 snd_hda_codec_write_cache(codec, nid, 0,
2855 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002856
2857 }
Mattc7d4b2f2005-06-27 14:59:41 +02002858 }
2859
Steve Longerbeam7b043892007-05-03 20:50:03 +02002860 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2861 spec->multiout.num_dacs,
2862 spec->multiout.dac_nids[0],
2863 spec->multiout.dac_nids[1],
2864 spec->multiout.dac_nids[2],
2865 spec->multiout.dac_nids[3],
2866 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002867 return 0;
2868}
2869
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002870/* create volume control/switch for the given prefx type */
2871static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2872{
2873 char name[32];
2874 int err;
2875
2876 sprintf(name, "%s Playback Volume", pfx);
2877 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2878 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2879 if (err < 0)
2880 return err;
2881 sprintf(name, "%s Playback Switch", pfx);
2882 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2883 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2884 if (err < 0)
2885 return err;
2886 return 0;
2887}
2888
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002889static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2890{
2891 if (!spec->multiout.hp_nid)
2892 spec->multiout.hp_nid = nid;
2893 else if (spec->multiout.num_dacs > 4) {
2894 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2895 return 1;
2896 } else {
2897 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2898 spec->multiout.num_dacs++;
2899 }
2900 return 0;
2901}
2902
2903static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2904{
2905 if (is_in_dac_nids(spec, nid))
2906 return 1;
2907 if (spec->multiout.hp_nid == nid)
2908 return 1;
2909 return 0;
2910}
2911
Mattc7d4b2f2005-06-27 14:59:41 +02002912/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002913static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002914 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002915{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002916 static const char *chname[4] = {
2917 "Front", "Surround", NULL /*CLFE*/, "Side"
2918 };
Matthew Ranostayd21995e2008-10-13 13:22:45 -04002919 hda_nid_t nid = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002920 int i, err;
2921
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002922 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002923 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002924
2925
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002926 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002927 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002928 continue;
2929
2930 nid = spec->multiout.dac_nids[i];
2931
2932 if (i == 2) {
2933 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002934 err = create_controls(spec, "Center", nid, 1);
2935 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002936 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002937 err = create_controls(spec, "LFE", nid, 2);
2938 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002939 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002940
2941 wid_caps = get_wcaps(codec, nid);
2942
2943 if (wid_caps & AC_WCAP_LR_SWAP) {
2944 err = stac92xx_add_control(spec,
2945 STAC_CTL_WIDGET_CLFE_SWITCH,
2946 "Swap Center/LFE Playback Switch", nid);
2947
2948 if (err < 0)
2949 return err;
2950 }
2951
Mattc7d4b2f2005-06-27 14:59:41 +02002952 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002953 err = create_controls(spec, chname[i], nid, 3);
2954 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002955 return err;
2956 }
2957 }
2958
Matthew Ranostayfedb7562008-09-23 21:46:30 -04002959 if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
2960 cfg->hp_outs && !spec->multiout.hp_nid)
2961 spec->multiout.hp_nid = nid;
2962
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002963 if (cfg->hp_outs > 1) {
2964 err = stac92xx_add_control(spec,
2965 STAC_CTL_WIDGET_HP_SWITCH,
Takashi Iwaid7a89432008-11-12 09:48:04 +01002966 "Headphone as Line Out Switch",
2967 cfg->hp_pins[cfg->hp_outs - 1]);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002968 if (err < 0)
2969 return err;
2970 }
2971
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002972 if (spec->line_switch) {
2973 nid = cfg->input_pins[AUTO_PIN_LINE];
2974 pincap = snd_hda_param_read(codec, nid,
2975 AC_PAR_PIN_CAP);
2976 if (pincap & AC_PINCAP_OUT) {
2977 err = stac92xx_add_control(spec,
2978 STAC_CTL_WIDGET_IO_SWITCH,
2979 "Line In as Output Switch", nid << 8);
2980 if (err < 0)
2981 return err;
2982 }
2983 }
Matt Porter403d1942005-11-29 15:00:51 +01002984
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002985 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002986 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002987 unsigned int mic_pin = AUTO_PIN_MIC;
2988again:
2989 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002990 def_conf = snd_hda_codec_read(codec, nid, 0,
2991 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002992 /* some laptops have an internal analog microphone
2993 * which can't be used as a output */
2994 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2995 pincap = snd_hda_param_read(codec, nid,
2996 AC_PAR_PIN_CAP);
2997 if (pincap & AC_PINCAP_OUT) {
2998 err = stac92xx_add_control(spec,
2999 STAC_CTL_WIDGET_IO_SWITCH,
3000 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003001 nid = snd_hda_codec_read(codec, nid, 0,
3002 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
3003 if (!check_in_dac_nids(spec, nid))
3004 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01003005 if (err < 0)
3006 return err;
3007 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003008 } else if (mic_pin == AUTO_PIN_MIC) {
3009 mic_pin = AUTO_PIN_FRONT_MIC;
3010 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01003011 }
3012 }
Matt Porter403d1942005-11-29 15:00:51 +01003013
Mattc7d4b2f2005-06-27 14:59:41 +02003014 return 0;
3015}
3016
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003017/* add playback controls for Speaker and HP outputs */
3018static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
3019 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02003020{
3021 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003022 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003023 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02003024
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003025 old_num_dacs = spec->multiout.num_dacs;
3026 for (i = 0; i < cfg->hp_outs; i++) {
3027 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
3028 if (wid_caps & AC_WCAP_UNSOL_CAP)
3029 spec->hp_detect = 1;
3030 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
3031 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
3032 if (check_in_dac_nids(spec, nid))
3033 nid = 0;
3034 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02003035 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003036 add_spec_dacs(spec, nid);
3037 }
3038 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02003039 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003040 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
3041 if (check_in_dac_nids(spec, nid))
3042 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003043 if (! nid)
3044 continue;
3045 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02003046 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02003047 for (i = 0; i < cfg->line_outs; i++) {
3048 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
3049 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
3050 if (check_in_dac_nids(spec, nid))
3051 nid = 0;
3052 if (! nid)
3053 continue;
3054 add_spec_dacs(spec, nid);
3055 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003056 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
3057 static const char *pfxs[] = {
3058 "Speaker", "External Speaker", "Speaker2",
3059 };
3060 err = create_controls(spec, pfxs[i - old_num_dacs],
3061 spec->multiout.dac_nids[i], 3);
3062 if (err < 0)
3063 return err;
3064 }
3065 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01003066 err = create_controls(spec, "Headphone",
3067 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003068 if (err < 0)
3069 return err;
3070 }
Mattc7d4b2f2005-06-27 14:59:41 +02003071
3072 return 0;
3073}
3074
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003075/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003076static const char *stac92xx_mono_labels[4] = {
3077 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003078};
3079
3080/* create mono mux for mono out on capable codecs */
3081static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
3082{
3083 struct sigmatel_spec *spec = codec->spec;
3084 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
3085 int i, num_cons;
3086 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
3087
3088 num_cons = snd_hda_get_connections(codec,
3089 spec->mono_nid,
3090 con_lst,
3091 HDA_MAX_NUM_INPUTS);
3092 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
3093 return -EINVAL;
3094
3095 for (i = 0; i < num_cons; i++) {
3096 mono_mux->items[mono_mux->num_items].label =
3097 stac92xx_mono_labels[i];
3098 mono_mux->items[mono_mux->num_items].index = i;
3099 mono_mux->num_items++;
3100 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003101
3102 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
3103 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003104}
3105
Matthew Ranostay89385032008-09-11 09:49:39 -04003106/* labels for amp mux outputs */
3107static const char *stac92xx_amp_labels[3] = {
Matthew Ranostay4b33c762008-10-10 09:07:23 -04003108 "Front Microphone", "Microphone", "Line In",
Matthew Ranostay89385032008-09-11 09:49:39 -04003109};
3110
3111/* create amp out controls mux on capable codecs */
3112static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
3113{
3114 struct sigmatel_spec *spec = codec->spec;
3115 struct hda_input_mux *amp_mux = &spec->private_amp_mux;
3116 int i, err;
3117
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003118 for (i = 0; i < spec->num_amps; i++) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003119 amp_mux->items[amp_mux->num_items].label =
3120 stac92xx_amp_labels[i];
3121 amp_mux->items[amp_mux->num_items].index = i;
3122 amp_mux->num_items++;
3123 }
3124
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003125 if (spec->num_amps > 1) {
3126 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
3127 "Amp Selector Capture Switch", 0);
3128 if (err < 0)
3129 return err;
3130 }
Matthew Ranostay89385032008-09-11 09:49:39 -04003131 return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
3132 "Amp Capture Volume",
3133 HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
3134}
3135
3136
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003137/* create PC beep volume controls */
3138static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3139 hda_nid_t nid)
3140{
3141 struct sigmatel_spec *spec = codec->spec;
3142 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3143 int err;
3144
3145 /* check for mute support for the the amp */
3146 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3147 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3148 "PC Beep Playback Switch",
3149 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3150 if (err < 0)
3151 return err;
3152 }
3153
3154 /* check to see if there is volume support for the amp */
3155 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3156 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
3157 "PC Beep Playback Volume",
3158 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3159 if (err < 0)
3160 return err;
3161 }
3162 return 0;
3163}
3164
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003165#ifdef CONFIG_SND_HDA_INPUT_BEEP
3166#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
3167
3168static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
3169 struct snd_ctl_elem_value *ucontrol)
3170{
3171 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3172 ucontrol->value.integer.value[0] = codec->beep->enabled;
3173 return 0;
3174}
3175
3176static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
3177 struct snd_ctl_elem_value *ucontrol)
3178{
3179 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3180 int enabled = !!ucontrol->value.integer.value[0];
3181 if (codec->beep->enabled != enabled) {
3182 codec->beep->enabled = enabled;
3183 return 1;
3184 }
3185 return 0;
3186}
3187
3188static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
3189 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3190 .info = stac92xx_dig_beep_switch_info,
3191 .get = stac92xx_dig_beep_switch_get,
3192 .put = stac92xx_dig_beep_switch_put,
3193};
3194
3195static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
3196{
3197 return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
3198 0, "PC Beep Playback Switch", 0);
3199}
3200#endif
3201
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003202static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3203{
3204 struct sigmatel_spec *spec = codec->spec;
3205 int wcaps, nid, i, err = 0;
3206
3207 for (i = 0; i < spec->num_muxes; i++) {
3208 nid = spec->mux_nids[i];
3209 wcaps = get_wcaps(codec, nid);
3210
3211 if (wcaps & AC_WCAP_OUT_AMP) {
3212 err = stac92xx_add_control_idx(spec,
3213 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
3214 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3215 if (err < 0)
3216 return err;
3217 }
3218 }
3219 return 0;
3220};
3221
Matthew Ranostayd9737752008-09-07 12:03:41 +02003222static const char *stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04003223 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02003224};
3225
3226static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
3227{
3228 struct sigmatel_spec *spec = codec->spec;
3229 struct hda_input_mux *spdif_mux = &spec->private_smux;
Matthew Ranostay65973632008-09-16 10:39:37 -04003230 const char **labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003231 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04003232 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003233
3234 num_cons = snd_hda_get_connections(codec,
3235 spec->smux_nids[0],
3236 con_lst,
3237 HDA_MAX_NUM_INPUTS);
Matthew Ranostay65973632008-09-16 10:39:37 -04003238 if (!num_cons)
Matthew Ranostayd9737752008-09-07 12:03:41 +02003239 return -EINVAL;
3240
Matthew Ranostay65973632008-09-16 10:39:37 -04003241 if (!labels)
3242 labels = stac92xx_spdif_labels;
3243
Matthew Ranostayd9737752008-09-07 12:03:41 +02003244 for (i = 0; i < num_cons; i++) {
Matthew Ranostay65973632008-09-16 10:39:37 -04003245 spdif_mux->items[spdif_mux->num_items].label = labels[i];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003246 spdif_mux->items[spdif_mux->num_items].index = i;
3247 spdif_mux->num_items++;
3248 }
3249
3250 return 0;
3251}
3252
Matt Porter8b657272006-10-26 17:12:59 +02003253/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01003254static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02003255 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
3256 "Digital Mic 3", "Digital Mic 4"
3257};
3258
3259/* create playback/capture controls for input pins on dmic capable codecs */
3260static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3261 const struct auto_pin_cfg *cfg)
3262{
3263 struct sigmatel_spec *spec = codec->spec;
3264 struct hda_input_mux *dimux = &spec->private_dimux;
3265 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003266 int err, i, j;
3267 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02003268
3269 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
3270 dimux->items[dimux->num_items].index = 0;
3271 dimux->num_items++;
3272
3273 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003274 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02003275 int index;
3276 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003277 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02003278 unsigned int def_conf;
3279
3280 def_conf = snd_hda_codec_read(codec,
3281 spec->dmic_nids[i],
3282 0,
3283 AC_VERB_GET_CONFIG_DEFAULT,
3284 0);
3285 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
3286 continue;
3287
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003288 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02003289 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003290 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02003291 con_lst,
3292 HDA_MAX_NUM_INPUTS);
3293 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003294 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02003295 index = j;
3296 goto found;
3297 }
3298 continue;
3299found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003300 wcaps = get_wcaps(codec, nid) &
3301 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003302
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003303 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003304 sprintf(name, "%s Capture Volume",
3305 stac92xx_dmic_labels[dimux->num_items]);
3306
3307 err = stac92xx_add_control(spec,
3308 STAC_CTL_WIDGET_VOL,
3309 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003310 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3311 (wcaps & AC_WCAP_OUT_AMP) ?
3312 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003313 if (err < 0)
3314 return err;
3315 }
3316
Matt Porter8b657272006-10-26 17:12:59 +02003317 dimux->items[dimux->num_items].label =
3318 stac92xx_dmic_labels[dimux->num_items];
3319 dimux->items[dimux->num_items].index = index;
3320 dimux->num_items++;
3321 }
3322
3323 return 0;
3324}
3325
Mattc7d4b2f2005-06-27 14:59:41 +02003326/* create playback/capture controls for input pins */
3327static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3328{
3329 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003330 struct hda_input_mux *imux = &spec->private_imux;
3331 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3332 int i, j, k;
3333
3334 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003335 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003336
Takashi Iwai314634b2006-09-21 11:56:18 +02003337 if (!cfg->input_pins[i])
3338 continue;
3339 index = -1;
3340 for (j = 0; j < spec->num_muxes; j++) {
3341 int num_cons;
3342 num_cons = snd_hda_get_connections(codec,
3343 spec->mux_nids[j],
3344 con_lst,
3345 HDA_MAX_NUM_INPUTS);
3346 for (k = 0; k < num_cons; k++)
3347 if (con_lst[k] == cfg->input_pins[i]) {
3348 index = k;
3349 goto found;
3350 }
Mattc7d4b2f2005-06-27 14:59:41 +02003351 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003352 continue;
3353 found:
3354 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3355 imux->items[imux->num_items].index = index;
3356 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003357 }
3358
Steve Longerbeam7b043892007-05-03 20:50:03 +02003359 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003360 /*
3361 * Set the current input for the muxes.
3362 * The STAC9221 has two input muxes with identical source
3363 * NID lists. Hopefully this won't get confused.
3364 */
3365 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003366 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3367 AC_VERB_SET_CONNECT_SEL,
3368 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003369 }
3370 }
3371
Mattc7d4b2f2005-06-27 14:59:41 +02003372 return 0;
3373}
3374
Mattc7d4b2f2005-06-27 14:59:41 +02003375static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3376{
3377 struct sigmatel_spec *spec = codec->spec;
3378 int i;
3379
3380 for (i = 0; i < spec->autocfg.line_outs; i++) {
3381 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3382 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3383 }
3384}
3385
3386static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3387{
3388 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003389 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003390
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003391 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3392 hda_nid_t pin;
3393 pin = spec->autocfg.hp_pins[i];
3394 if (pin) /* connect to front */
3395 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3396 }
3397 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3398 hda_nid_t pin;
3399 pin = spec->autocfg.speaker_pins[i];
3400 if (pin) /* connect to front */
3401 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3402 }
Mattc7d4b2f2005-06-27 14:59:41 +02003403}
3404
Matt Porter3cc08dc2006-01-23 15:27:49 +01003405static 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 +02003406{
3407 struct sigmatel_spec *spec = codec->spec;
3408 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003409 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003410
Matt Porter8b657272006-10-26 17:12:59 +02003411 if ((err = snd_hda_parse_pin_def_config(codec,
3412 &spec->autocfg,
3413 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003414 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003415 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003416 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003417
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003418 /* If we have no real line-out pin and multiple hp-outs, HPs should
3419 * be set up as multi-channel outputs.
3420 */
3421 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3422 spec->autocfg.hp_outs > 1) {
3423 /* Copy hp_outs to line_outs, backup line_outs in
3424 * speaker_outs so that the following routines can handle
3425 * HP pins as primary outputs.
3426 */
3427 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3428 sizeof(spec->autocfg.line_out_pins));
3429 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3430 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3431 sizeof(spec->autocfg.hp_pins));
3432 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3433 hp_speaker_swap = 1;
3434 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003435 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003436 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3437 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003438 u32 caps = query_amp_caps(codec,
3439 spec->autocfg.mono_out_pin, dir);
3440 hda_nid_t conn_list[1];
3441
3442 /* get the mixer node and then the mono mux if it exists */
3443 if (snd_hda_get_connections(codec,
3444 spec->autocfg.mono_out_pin, conn_list, 1) &&
3445 snd_hda_get_connections(codec, conn_list[0],
3446 conn_list, 1)) {
3447
3448 int wcaps = get_wcaps(codec, conn_list[0]);
3449 int wid_type = (wcaps & AC_WCAP_TYPE)
3450 >> AC_WCAP_TYPE_SHIFT;
3451 /* LR swap check, some stac925x have a mux that
3452 * changes the DACs output path instead of the
3453 * mono-mux path.
3454 */
3455 if (wid_type == AC_WID_AUD_SEL &&
3456 !(wcaps & AC_WCAP_LR_SWAP))
3457 spec->mono_nid = conn_list[0];
3458 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003459 if (dir) {
3460 hda_nid_t nid = spec->autocfg.mono_out_pin;
3461
3462 /* most mono outs have a least a mute/unmute switch */
3463 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3464 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3465 "Mono Playback Switch",
3466 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003467 if (err < 0)
3468 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003469 /* check for volume support for the amp */
3470 if ((caps & AC_AMPCAP_NUM_STEPS)
3471 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3472 err = stac92xx_add_control(spec,
3473 STAC_CTL_WIDGET_VOL,
3474 "Mono Playback Volume",
3475 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3476 if (err < 0)
3477 return err;
3478 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003479 }
3480
3481 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3482 AC_PINCTL_OUT_EN);
3483 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003484
Matt Porter403d1942005-11-29 15:00:51 +01003485 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3486 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003487 if (spec->multiout.num_dacs == 0)
3488 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3489 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003490
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003491 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3492
3493 if (err < 0)
3494 return err;
3495
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003496 /* setup analog beep controls */
3497 if (spec->anabeep_nid > 0) {
3498 err = stac92xx_auto_create_beep_ctls(codec,
3499 spec->anabeep_nid);
3500 if (err < 0)
3501 return err;
3502 }
3503
3504 /* setup digital beep controls and input device */
3505#ifdef CONFIG_SND_HDA_INPUT_BEEP
3506 if (spec->digbeep_nid > 0) {
3507 hda_nid_t nid = spec->digbeep_nid;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003508 unsigned int caps;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003509
3510 err = stac92xx_auto_create_beep_ctls(codec, nid);
3511 if (err < 0)
3512 return err;
3513 err = snd_hda_attach_beep_device(codec, nid);
3514 if (err < 0)
3515 return err;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003516 /* if no beep switch is available, make its own one */
3517 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3518 if (codec->beep &&
3519 !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
3520 err = stac92xx_beep_switch_ctl(codec);
3521 if (err < 0)
3522 return err;
3523 }
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003524 }
3525#endif
3526
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003527 if (hp_speaker_swap == 1) {
3528 /* Restore the hp_outs and line_outs */
3529 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3530 sizeof(spec->autocfg.line_out_pins));
3531 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3532 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3533 sizeof(spec->autocfg.speaker_pins));
3534 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3535 memset(spec->autocfg.speaker_pins, 0,
3536 sizeof(spec->autocfg.speaker_pins));
3537 spec->autocfg.speaker_outs = 0;
3538 }
3539
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003540 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3541
3542 if (err < 0)
3543 return err;
3544
3545 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3546
3547 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003548 return err;
3549
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003550 if (spec->mono_nid > 0) {
3551 err = stac92xx_auto_create_mono_output_ctls(codec);
3552 if (err < 0)
3553 return err;
3554 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003555 if (spec->num_amps > 0) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003556 err = stac92xx_auto_create_amp_output_ctls(codec);
3557 if (err < 0)
3558 return err;
3559 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003560 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02003561 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3562 &spec->autocfg)) < 0)
3563 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003564 if (spec->num_muxes > 0) {
3565 err = stac92xx_auto_create_mux_input_ctls(codec);
3566 if (err < 0)
3567 return err;
3568 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003569 if (spec->num_smuxes > 0) {
3570 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3571 if (err < 0)
3572 return err;
3573 }
Matt Porter8b657272006-10-26 17:12:59 +02003574
Mattc7d4b2f2005-06-27 14:59:41 +02003575 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003576 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003577 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003578
Takashi Iwai82bc9552006-03-21 11:24:42 +01003579 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003580 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003581 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003582 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003583
Takashi Iwai603c4012008-07-30 15:01:44 +02003584 if (spec->kctls.list)
3585 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003586
3587 spec->input_mux = &spec->private_imux;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003588 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003589 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003590 spec->mono_mux = &spec->private_mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -04003591 spec->amp_mux = &spec->private_amp_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003592 return 1;
3593}
3594
Takashi Iwai82bc9552006-03-21 11:24:42 +01003595/* add playback controls for HP output */
3596static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3597 struct auto_pin_cfg *cfg)
3598{
3599 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003600 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003601 unsigned int wid_caps;
3602
3603 if (! pin)
3604 return 0;
3605
3606 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003607 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003608 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003609
3610 return 0;
3611}
3612
Richard Fish160ea0d2006-09-06 13:58:25 +02003613/* add playback controls for LFE output */
3614static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3615 struct auto_pin_cfg *cfg)
3616{
3617 struct sigmatel_spec *spec = codec->spec;
3618 int err;
3619 hda_nid_t lfe_pin = 0x0;
3620 int i;
3621
3622 /*
3623 * search speaker outs and line outs for a mono speaker pin
3624 * with an amp. If one is found, add LFE controls
3625 * for it.
3626 */
3627 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3628 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003629 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003630 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3631 if (wcaps == AC_WCAP_OUT_AMP)
3632 /* found a mono speaker with an amp, must be lfe */
3633 lfe_pin = pin;
3634 }
3635
3636 /* if speaker_outs is 0, then speakers may be in line_outs */
3637 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3638 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3639 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003640 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003641 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003642 AC_VERB_GET_CONFIG_DEFAULT,
3643 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003644 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003645 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003646 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3647 if (wcaps == AC_WCAP_OUT_AMP)
3648 /* found a mono speaker with an amp,
3649 must be lfe */
3650 lfe_pin = pin;
3651 }
3652 }
3653 }
3654
3655 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003656 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003657 if (err < 0)
3658 return err;
3659 }
3660
3661 return 0;
3662}
3663
Mattc7d4b2f2005-06-27 14:59:41 +02003664static int stac9200_parse_auto_config(struct hda_codec *codec)
3665{
3666 struct sigmatel_spec *spec = codec->spec;
3667 int err;
3668
Kailang Yangdf694da2005-12-05 19:42:22 +01003669 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003670 return err;
3671
3672 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3673 return err;
3674
Takashi Iwai82bc9552006-03-21 11:24:42 +01003675 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3676 return err;
3677
Richard Fish160ea0d2006-09-06 13:58:25 +02003678 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3679 return err;
3680
Takashi Iwai355a0ec2008-11-11 16:46:19 +01003681 if (spec->num_muxes > 0) {
3682 err = stac92xx_auto_create_mux_input_ctls(codec);
3683 if (err < 0)
3684 return err;
3685 }
3686
Takashi Iwai82bc9552006-03-21 11:24:42 +01003687 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003688 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003689 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003690 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003691
Takashi Iwai603c4012008-07-30 15:01:44 +02003692 if (spec->kctls.list)
3693 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003694
3695 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003696 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003697
3698 return 1;
3699}
3700
Sam Revitch62fe78e2006-05-10 15:09:17 +02003701/*
3702 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3703 * funky external mute control using GPIO pins.
3704 */
3705
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003706static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003707 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003708{
3709 unsigned int gpiostate, gpiomask, gpiodir;
3710
3711 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3712 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003713 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003714
3715 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3716 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003717 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003718
3719 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3720 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003721 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003722
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003723 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003724 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3725
3726 snd_hda_codec_write(codec, codec->afg, 0,
3727 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003728 snd_hda_codec_read(codec, codec->afg, 0,
3729 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003730
3731 msleep(1);
3732
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003733 snd_hda_codec_read(codec, codec->afg, 0,
3734 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003735}
3736
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003737static int stac92xx_add_jack(struct hda_codec *codec,
3738 hda_nid_t nid, int type)
3739{
Takashi Iwaie4973e12008-11-18 09:32:42 +01003740#ifdef CONFIG_SND_JACK
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003741 struct sigmatel_spec *spec = codec->spec;
3742 struct sigmatel_jack *jack;
3743 int def_conf = snd_hda_codec_read(codec, nid,
3744 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
3745 int connectivity = get_defcfg_connect(def_conf);
3746 char name[32];
3747
3748 if (connectivity && connectivity != AC_JACK_PORT_FIXED)
3749 return 0;
3750
3751 snd_array_init(&spec->jacks, sizeof(*jack), 32);
3752 jack = snd_array_new(&spec->jacks);
3753 if (!jack)
3754 return -ENOMEM;
3755 jack->nid = nid;
3756 jack->type = type;
3757
3758 sprintf(name, "%s at %s %s Jack",
3759 snd_hda_get_jack_type(def_conf),
3760 snd_hda_get_jack_connectivity(def_conf),
3761 snd_hda_get_jack_location(def_conf));
3762
3763 return snd_jack_new(codec->bus->card, name, type, &jack->jack);
Takashi Iwaie4973e12008-11-18 09:32:42 +01003764#else
3765 return 0;
3766#endif
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003767}
3768
3769static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
3770 int data)
3771{
3772 struct sigmatel_event *event;
3773
3774 snd_array_init(&spec->events, sizeof(*event), 32);
3775 event = snd_array_new(&spec->events);
3776 if (!event)
3777 return -ENOMEM;
3778 event->nid = nid;
3779 event->data = data;
3780
3781 return 0;
3782}
3783
3784static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid)
3785{
3786 struct sigmatel_spec *spec = codec->spec;
3787 struct sigmatel_event *events = spec->events.list;
3788 if (events) {
3789 int i;
3790 for (i = 0; i < spec->events.used; i++)
3791 if (events[i].nid == nid)
3792 return events[i].data;
3793 }
3794 return 0;
3795}
3796
Takashi Iwai314634b2006-09-21 11:56:18 +02003797static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3798 unsigned int event)
3799{
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003800 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003801 snd_hda_codec_write_cache(codec, nid, 0,
3802 AC_VERB_SET_UNSOLICITED_ENABLE,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003803 (AC_USRSP_EN | event | nid));
3804 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003805}
3806
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003807static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3808{
3809 int i;
3810 for (i = 0; i < cfg->hp_outs; i++)
3811 if (cfg->hp_pins[i] == nid)
3812 return 1; /* nid is a HP-Out */
3813
3814 return 0; /* nid is not a HP-Out */
3815};
3816
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003817static void stac92xx_power_down(struct hda_codec *codec)
3818{
3819 struct sigmatel_spec *spec = codec->spec;
3820
3821 /* power down inactive DACs */
3822 hda_nid_t *dac;
3823 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003824 if (!is_in_dac_nids(spec, *dac) &&
3825 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003826 snd_hda_codec_write_cache(codec, *dac, 0,
3827 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3828}
3829
Mattc7d4b2f2005-06-27 14:59:41 +02003830static int stac92xx_init(struct hda_codec *codec)
3831{
3832 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003833 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie4973e12008-11-18 09:32:42 +01003834 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003835
Mattc7d4b2f2005-06-27 14:59:41 +02003836 snd_hda_sequence_write(codec, spec->init);
3837
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003838 /* power down adcs initially */
3839 if (spec->powerdown_adcs)
3840 for (i = 0; i < spec->num_adcs; i++)
3841 snd_hda_codec_write_cache(codec,
3842 spec->adc_nids[i], 0,
3843 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003844 /* set up pins */
3845 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003846 /* Enable unsolicited responses on the HP widget */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003847 for (i = 0; i < cfg->hp_outs; i++) {
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003848 hda_nid_t nid = cfg->hp_pins[i];
3849 enable_pin_detect(codec, nid, STAC_HP_EVENT | nid);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003850 }
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003851 /* force to enable the first line-out; the others are set up
3852 * in unsol_event
3853 */
3854 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003855 AC_PINCTL_OUT_EN);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003856 /* fake event to set up pins */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003857 codec->patch_ops.unsol_event(codec,
3858 (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003859 } else {
3860 stac92xx_auto_init_multi_out(codec);
3861 stac92xx_auto_init_hp_out(codec);
3862 }
3863 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003864 hda_nid_t nid = cfg->input_pins[i];
3865 if (nid) {
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01003866 unsigned int pinctl;
3867 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
3868 /* for mic pins, force to initialize */
3869 pinctl = stac92xx_get_vref(codec, nid);
3870 } else {
3871 pinctl = snd_hda_codec_read(codec, nid, 0,
3872 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3873 /* if PINCTL already set then skip */
3874 if (pinctl & AC_PINCTL_IN_EN)
3875 continue;
3876 }
3877 pinctl |= AC_PINCTL_IN_EN;
Takashi Iwaic960a032006-03-23 17:06:28 +01003878 stac92xx_auto_set_pinctl(codec, nid, pinctl);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003879 enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid);
Takashi Iwaic960a032006-03-23 17:06:28 +01003880 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003881 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003882 for (i = 0; i < spec->num_dmics; i++)
3883 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3884 AC_PINCTL_IN_EN);
3885 for (i = 0; i < spec->num_pwrs; i++) {
3886 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3887 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3888 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3889 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003890 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3891 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003892 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003893 /* outputs are only ports capable of power management
3894 * any attempts on powering down a input port cause the
3895 * referenced VREF to act quirky.
3896 */
3897 if (pinctl & AC_PINCTL_IN_EN)
3898 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003899 /* skip any ports that don't have jacks since presence
3900 * detection is useless */
3901 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003902 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003903 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3904 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3905 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003906 if (spec->dac_list)
3907 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003908 if (cfg->dig_out_pin)
3909 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3910 AC_PINCTL_OUT_EN);
3911 if (cfg->dig_in_pin)
3912 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3913 AC_PINCTL_IN_EN);
3914
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003915 stac_gpio_set(codec, spec->gpio_mask,
3916 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003917
Mattc7d4b2f2005-06-27 14:59:41 +02003918 return 0;
3919}
3920
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003921static void stac92xx_free_jacks(struct hda_codec *codec)
3922{
Takashi Iwaie4973e12008-11-18 09:32:42 +01003923#ifdef CONFIG_SND_JACK
Takashi Iwaib94d3532008-11-21 09:08:06 +01003924 /* free jack instances manually when clearing/reconfiguring */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003925 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaib94d3532008-11-21 09:08:06 +01003926 if (!codec->bus->shutdown && spec->jacks.list) {
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003927 struct sigmatel_jack *jacks = spec->jacks.list;
3928 int i;
3929 for (i = 0; i < spec->jacks.used; i++)
3930 snd_device_free(codec->bus->card, &jacks[i].jack);
3931 }
3932 snd_array_free(&spec->jacks);
Takashi Iwaie4973e12008-11-18 09:32:42 +01003933#endif
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003934}
3935
Takashi Iwai603c4012008-07-30 15:01:44 +02003936static void stac92xx_free_kctls(struct hda_codec *codec)
3937{
3938 struct sigmatel_spec *spec = codec->spec;
3939
3940 if (spec->kctls.list) {
3941 struct snd_kcontrol_new *kctl = spec->kctls.list;
3942 int i;
3943 for (i = 0; i < spec->kctls.used; i++)
3944 kfree(kctl[i].name);
3945 }
3946 snd_array_free(&spec->kctls);
3947}
3948
Matt2f2f4252005-04-13 14:45:30 +02003949static void stac92xx_free(struct hda_codec *codec)
3950{
Mattc7d4b2f2005-06-27 14:59:41 +02003951 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003952
3953 if (! spec)
3954 return;
3955
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01003956 kfree(spec->pin_configs);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003957 stac92xx_free_jacks(codec);
3958 snd_array_free(&spec->events);
Richard Fish11b44bb2006-08-23 18:31:34 +02003959
Mattc7d4b2f2005-06-27 14:59:41 +02003960 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003961 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003962}
3963
Matt4e550962005-07-04 17:51:39 +02003964static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3965 unsigned int flag)
3966{
3967 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3968 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003969
Takashi Iwaif9acba42007-05-29 18:01:06 +02003970 if (pin_ctl & AC_PINCTL_IN_EN) {
3971 /*
3972 * we need to check the current set-up direction of
3973 * shared input pins since they can be switched via
3974 * "xxx as Output" mixer switch
3975 */
3976 struct sigmatel_spec *spec = codec->spec;
3977 struct auto_pin_cfg *cfg = &spec->autocfg;
3978 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3979 spec->line_switch) ||
3980 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3981 spec->mic_switch))
3982 return;
3983 }
3984
Steve Longerbeam7b043892007-05-03 20:50:03 +02003985 /* if setting pin direction bits, clear the current
3986 direction bits first */
3987 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3988 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3989
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003990 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003991 AC_VERB_SET_PIN_WIDGET_CONTROL,
3992 pin_ctl | flag);
3993}
3994
3995static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3996 unsigned int flag)
3997{
3998 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3999 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004000 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02004001 AC_VERB_SET_PIN_WIDGET_CONTROL,
4002 pin_ctl & ~flag);
4003}
4004
Jiang Zhe40c1d302007-11-12 13:05:16 +01004005static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02004006{
4007 if (!nid)
4008 return 0;
4009 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01004010 & (1 << 31)) {
4011 unsigned int pinctl;
4012 pinctl = snd_hda_codec_read(codec, nid, 0,
4013 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4014 if (pinctl & AC_PINCTL_IN_EN)
4015 return 0; /* mic- or line-input */
4016 else
4017 return 1; /* HP-output */
4018 }
Takashi Iwai314634b2006-09-21 11:56:18 +02004019 return 0;
4020}
4021
Takashi Iwaid7a89432008-11-12 09:48:04 +01004022/* return non-zero if the hp-pin of the given array index isn't
4023 * a jack-detection target
4024 */
4025static int no_hp_sensing(struct sigmatel_spec *spec, int i)
4026{
4027 struct auto_pin_cfg *cfg = &spec->autocfg;
4028
4029 /* ignore sensing of shared line and mic jacks */
4030 if (spec->line_switch &&
4031 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
4032 return 1;
4033 if (spec->mic_switch &&
4034 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
4035 return 1;
4036 /* ignore if the pin is set as line-out */
4037 if (cfg->hp_pins[i] == spec->hp_switch)
4038 return 1;
4039 return 0;
4040}
4041
Takashi Iwai314634b2006-09-21 11:56:18 +02004042static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02004043{
4044 struct sigmatel_spec *spec = codec->spec;
4045 struct auto_pin_cfg *cfg = &spec->autocfg;
4046 int i, presence;
4047
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004048 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004049 if (spec->gpio_mute)
4050 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
4051 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
4052
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004053 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02004054 if (presence)
4055 break;
Takashi Iwaid7a89432008-11-12 09:48:04 +01004056 if (no_hp_sensing(spec, i))
4057 continue;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004058 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004059 }
Matt4e550962005-07-04 17:51:39 +02004060
4061 if (presence) {
Takashi Iwaid7a89432008-11-12 09:48:04 +01004062 /* disable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02004063 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004064 stac92xx_reset_pinctl(codec, spec->hp_switch,
4065 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02004066 for (i = 0; i < cfg->line_outs; i++)
4067 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
4068 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004069 for (i = 0; i < cfg->speaker_outs; i++)
4070 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
4071 AC_PINCTL_OUT_EN);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004072 if (spec->eapd_mask && spec->eapd_switch)
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004073 stac_gpio_set(codec, spec->gpio_mask,
4074 spec->gpio_dir, spec->gpio_data &
4075 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02004076 } else {
Takashi Iwaid7a89432008-11-12 09:48:04 +01004077 /* enable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02004078 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004079 stac92xx_set_pinctl(codec, spec->hp_switch,
4080 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02004081 for (i = 0; i < cfg->line_outs; i++)
4082 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
4083 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004084 for (i = 0; i < cfg->speaker_outs; i++)
4085 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
4086 AC_PINCTL_OUT_EN);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004087 if (spec->eapd_mask && spec->eapd_switch)
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004088 stac_gpio_set(codec, spec->gpio_mask,
4089 spec->gpio_dir, spec->gpio_data |
4090 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02004091 }
Takashi Iwaid7a89432008-11-12 09:48:04 +01004092 /* toggle hp outs */
4093 for (i = 0; i < cfg->hp_outs; i++) {
4094 unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
4095 if (no_hp_sensing(spec, i))
4096 continue;
4097 if (presence)
4098 stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
4099 else
4100 stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
4101 }
Matt4e550962005-07-04 17:51:39 +02004102}
4103
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004104static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
4105{
4106 struct sigmatel_spec *spec = codec->spec;
4107 hda_nid_t nid = spec->pwr_nids[idx];
4108 int presence, val;
4109 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
4110 & 0x000000ff;
4111 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004112
4113 /* several codecs have two power down bits */
4114 if (spec->pwr_mapping)
4115 idx = spec->pwr_mapping[idx];
4116 else
4117 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004118
4119 if (presence)
4120 val &= ~idx;
4121 else
4122 val |= idx;
4123
4124 /* power down unused output ports */
4125 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004126}
4127
4128static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
4129{
4130 struct sigmatel_spec *spec = codec->spec;
4131 struct sigmatel_jack *jacks = spec->jacks.list;
4132
4133 if (jacks) {
4134 int i;
4135 for (i = 0; i < spec->jacks.used; i++) {
4136 if (jacks->nid == nid) {
4137 unsigned int pin_ctl =
4138 snd_hda_codec_read(codec, nid,
4139 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
4140 0x00);
4141 int type = jacks->type;
4142 if (type == (SND_JACK_LINEOUT
4143 | SND_JACK_HEADPHONE))
4144 type = (pin_ctl & AC_PINCTL_HP_EN)
4145 ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
4146 snd_jack_report(jacks->jack,
4147 get_hp_pin_presence(codec, nid)
4148 ? type : 0);
4149 }
4150 jacks++;
4151 }
4152 }
4153}
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004154
Takashi Iwai314634b2006-09-21 11:56:18 +02004155static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
4156{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004157 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004158 int event = (res >> 26) & 0x70;
4159 int nid = res >> 26 & 0x0f;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004160
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004161 switch (event) {
Takashi Iwai314634b2006-09-21 11:56:18 +02004162 case STAC_HP_EVENT:
4163 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004164 /* fallthru */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004165 case STAC_INSERT_EVENT:
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004166 case STAC_PWR_EVENT:
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004167 if (nid) {
4168 if (spec->num_pwrs > 0)
4169 stac92xx_pin_sense(codec, nid);
4170 stac92xx_report_jack(codec, nid);
4171 }
Matthew Ranostay72474be2008-10-09 09:32:17 -04004172 break;
4173 case STAC_VREF_EVENT: {
4174 int data = snd_hda_codec_read(codec, codec->afg, 0,
4175 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004176 int idx = stac92xx_event_data(codec, nid);
Matthew Ranostay72474be2008-10-09 09:32:17 -04004177 /* toggle VREF state based on GPIOx status */
4178 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
4179 !!(data & (1 << idx)));
4180 break;
4181 }
Takashi Iwai314634b2006-09-21 11:56:18 +02004182 }
4183}
4184
Takashi Iwaicb53c622007-08-10 17:21:45 +02004185#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004186static int stac92xx_resume(struct hda_codec *codec)
4187{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004188 struct sigmatel_spec *spec = codec->spec;
4189
Richard Fish11b44bb2006-08-23 18:31:34 +02004190 stac92xx_set_config_regs(codec);
Takashi Iwai2c885872008-11-18 09:36:55 +01004191 stac92xx_init(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004192 snd_hda_codec_resume_amp(codec);
4193 snd_hda_codec_resume_cache(codec);
Takashi Iwai2c885872008-11-18 09:36:55 +01004194 /* fake event to set up pins again to override cached values */
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004195 if (spec->hp_detect)
Takashi Iwai2c885872008-11-18 09:36:55 +01004196 codec->patch_ops.unsol_event(codec,
4197 (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
Mattff6fdc32005-06-27 15:06:52 +02004198 return 0;
4199}
Matthew Ranostayc6798d22008-11-18 20:54:17 -05004200
4201static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
4202{
4203 struct sigmatel_spec *spec = codec->spec;
4204 if (spec->eapd_mask)
4205 stac_gpio_set(codec, spec->gpio_mask,
4206 spec->gpio_dir, spec->gpio_data &
4207 ~spec->eapd_mask);
4208 return 0;
4209}
Mattff6fdc32005-06-27 15:06:52 +02004210#endif
4211
Matt2f2f4252005-04-13 14:45:30 +02004212static struct hda_codec_ops stac92xx_patch_ops = {
4213 .build_controls = stac92xx_build_controls,
4214 .build_pcms = stac92xx_build_pcms,
4215 .init = stac92xx_init,
4216 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02004217 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004218#ifdef SND_HDA_NEEDS_RESUME
Matthew Ranostayc6798d22008-11-18 20:54:17 -05004219 .suspend = stac92xx_suspend,
Mattff6fdc32005-06-27 15:06:52 +02004220 .resume = stac92xx_resume,
4221#endif
Matt2f2f4252005-04-13 14:45:30 +02004222};
4223
4224static int patch_stac9200(struct hda_codec *codec)
4225{
4226 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004227 int err;
Matt2f2f4252005-04-13 14:45:30 +02004228
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004229 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004230 if (spec == NULL)
4231 return -ENOMEM;
4232
4233 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004234 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004235 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004236 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
4237 stac9200_models,
4238 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02004239 if (spec->board_config < 0) {
4240 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
4241 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004242 } else
4243 err = stac_save_pin_cfgs(codec,
4244 stac9200_brd_tbl[spec->board_config]);
4245 if (err < 0) {
4246 stac92xx_free(codec);
4247 return err;
Matt Porter403d1942005-11-29 15:00:51 +01004248 }
Matt2f2f4252005-04-13 14:45:30 +02004249
4250 spec->multiout.max_channels = 2;
4251 spec->multiout.num_dacs = 1;
4252 spec->multiout.dac_nids = stac9200_dac_nids;
4253 spec->adc_nids = stac9200_adc_nids;
4254 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02004255 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02004256 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004257 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004258 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004259
Tobin Davisbf277782008-02-03 20:31:47 +01004260 if (spec->board_config == STAC_9200_GATEWAY ||
4261 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02004262 spec->init = stac9200_eapd_init;
4263 else
4264 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004265 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004266
Takashi Iwai117f2572008-03-18 09:53:23 +01004267 if (spec->board_config == STAC_9200_PANASONIC) {
4268 spec->gpio_mask = spec->gpio_dir = 0x09;
4269 spec->gpio_data = 0x00;
4270 }
4271
Mattc7d4b2f2005-06-27 14:59:41 +02004272 err = stac9200_parse_auto_config(codec);
4273 if (err < 0) {
4274 stac92xx_free(codec);
4275 return err;
4276 }
Matt2f2f4252005-04-13 14:45:30 +02004277
4278 codec->patch_ops = stac92xx_patch_ops;
4279
4280 return 0;
4281}
4282
Tobin Davis8e21c342007-01-08 11:04:17 +01004283static int patch_stac925x(struct hda_codec *codec)
4284{
4285 struct sigmatel_spec *spec;
4286 int err;
4287
4288 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4289 if (spec == NULL)
4290 return -ENOMEM;
4291
4292 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004293 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01004294 spec->pin_nids = stac925x_pin_nids;
4295 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
4296 stac925x_models,
4297 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004298 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01004299 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02004300 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
4301 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01004302 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004303 } else
4304 err = stac_save_pin_cfgs(codec,
4305 stac925x_brd_tbl[spec->board_config]);
4306 if (err < 0) {
4307 stac92xx_free(codec);
4308 return err;
Tobin Davis8e21c342007-01-08 11:04:17 +01004309 }
4310
4311 spec->multiout.max_channels = 2;
4312 spec->multiout.num_dacs = 1;
4313 spec->multiout.dac_nids = stac925x_dac_nids;
4314 spec->adc_nids = stac925x_adc_nids;
4315 spec->mux_nids = stac925x_mux_nids;
4316 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004317 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004318 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02004319 switch (codec->vendor_id) {
4320 case 0x83847632: /* STAC9202 */
4321 case 0x83847633: /* STAC9202D */
4322 case 0x83847636: /* STAC9251 */
4323 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02004324 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02004325 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004326 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
4327 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02004328 break;
4329 default:
4330 spec->num_dmics = 0;
4331 break;
4332 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004333
4334 spec->init = stac925x_core_init;
4335 spec->mixer = stac925x_mixer;
4336
4337 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004338 if (!err) {
4339 if (spec->board_config < 0) {
4340 printk(KERN_WARNING "hda_codec: No auto-config is "
4341 "available, default to model=ref\n");
4342 spec->board_config = STAC_925x_REF;
4343 goto again;
4344 }
4345 err = -EINVAL;
4346 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004347 if (err < 0) {
4348 stac92xx_free(codec);
4349 return err;
4350 }
4351
4352 codec->patch_ops = stac92xx_patch_ops;
4353
4354 return 0;
4355}
4356
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004357static struct hda_input_mux stac92hd73xx_dmux = {
4358 .num_items = 4,
4359 .items = {
4360 { "Analog Inputs", 0x0b },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004361 { "Digital Mic 1", 0x09 },
4362 { "Digital Mic 2", 0x0a },
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004363 { "CD", 0x08 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004364 }
4365};
4366
4367static int patch_stac92hd73xx(struct hda_codec *codec)
4368{
4369 struct sigmatel_spec *spec;
4370 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
4371 int err = 0;
4372
4373 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4374 if (spec == NULL)
4375 return -ENOMEM;
4376
4377 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02004378 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004379 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
4380 spec->pin_nids = stac92hd73xx_pin_nids;
4381 spec->board_config = snd_hda_check_board_config(codec,
4382 STAC_92HD73XX_MODELS,
4383 stac92hd73xx_models,
4384 stac92hd73xx_cfg_tbl);
4385again:
4386 if (spec->board_config < 0) {
4387 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4388 " STAC92HD73XX, using BIOS defaults\n");
4389 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004390 } else
4391 err = stac_save_pin_cfgs(codec,
4392 stac92hd73xx_brd_tbl[spec->board_config]);
4393 if (err < 0) {
4394 stac92xx_free(codec);
4395 return err;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004396 }
4397
4398 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
4399 conn, STAC92HD73_DAC_COUNT + 2) - 1;
4400
4401 if (spec->multiout.num_dacs < 0) {
4402 printk(KERN_WARNING "hda_codec: Could not determine "
4403 "number of channels defaulting to DAC count\n");
4404 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
4405 }
4406
4407 switch (spec->multiout.num_dacs) {
4408 case 0x3: /* 6 Channel */
4409 spec->mixer = stac92hd73xx_6ch_mixer;
4410 spec->init = stac92hd73xx_6ch_core_init;
4411 break;
4412 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004413 spec->mixer = stac92hd73xx_8ch_mixer;
4414 spec->init = stac92hd73xx_8ch_core_init;
4415 break;
4416 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004417 spec->mixer = stac92hd73xx_10ch_mixer;
4418 spec->init = stac92hd73xx_10ch_core_init;
4419 };
4420
4421 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
4422 spec->aloopback_mask = 0x01;
4423 spec->aloopback_shift = 8;
4424
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004425 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004426 spec->mux_nids = stac92hd73xx_mux_nids;
4427 spec->adc_nids = stac92hd73xx_adc_nids;
4428 spec->dmic_nids = stac92hd73xx_dmic_nids;
4429 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004430 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostay89385032008-09-11 09:49:39 -04004431 spec->amp_nids = stac92hd73xx_amp_nids;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004432 spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004433
4434 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
4435 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004436 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004437 memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
4438 sizeof(stac92hd73xx_dmux));
4439
Matthew Ranostaya7662642008-02-21 07:51:14 +01004440 switch (spec->board_config) {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004441 case STAC_DELL_EQ:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004442 spec->init = dell_eq_core_init;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004443 /* fallthru */
4444 case STAC_DELL_M6:
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004445 spec->num_smuxes = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004446 spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
4447 spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004448 spec->eapd_switch = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004449 spec->num_amps = 1;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004450
4451 if (!spec->init)
4452 spec->init = dell_m6_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004453 switch (codec->subsystem_id) {
4454 case 0x1028025e: /* Analog Mics */
4455 case 0x1028025f:
4456 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4457 spec->num_dmics = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004458 spec->private_dimux.num_items = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004459 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01004460 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004461 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004462 case 0x10280254:
4463 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01004464 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4465 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004466 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004467 break;
4468 case 0x10280256: /* Both */
4469 case 0x10280057:
4470 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4471 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4472 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004473 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004474 break;
4475 }
4476 break;
4477 default:
4478 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004479 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004480 spec->eapd_switch = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004481 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004482 if (spec->board_config > STAC_92HD73XX_REF) {
4483 /* GPIO0 High = Enable EAPD */
4484 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
4485 spec->gpio_data = 0x01;
4486 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004487 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004488
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004489 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
4490 spec->pwr_nids = stac92hd73xx_pwr_nids;
4491
Matthew Ranostayd9737752008-09-07 12:03:41 +02004492 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004493
4494 if (!err) {
4495 if (spec->board_config < 0) {
4496 printk(KERN_WARNING "hda_codec: No auto-config is "
4497 "available, default to model=ref\n");
4498 spec->board_config = STAC_92HD73XX_REF;
4499 goto again;
4500 }
4501 err = -EINVAL;
4502 }
4503
4504 if (err < 0) {
4505 stac92xx_free(codec);
4506 return err;
4507 }
4508
4509 codec->patch_ops = stac92xx_patch_ops;
4510
4511 return 0;
4512}
4513
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004514static struct hda_input_mux stac92hd83xxx_dmux = {
4515 .num_items = 3,
4516 .items = {
4517 { "Analog Inputs", 0x03 },
4518 { "Digital Mic 1", 0x04 },
4519 { "Digital Mic 2", 0x05 },
4520 }
4521};
4522
4523static int patch_stac92hd83xxx(struct hda_codec *codec)
4524{
4525 struct sigmatel_spec *spec;
4526 int err;
4527
4528 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4529 if (spec == NULL)
4530 return -ENOMEM;
4531
4532 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004533 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004534 spec->mono_nid = 0x19;
4535 spec->digbeep_nid = 0x21;
4536 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4537 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4538 spec->adc_nids = stac92hd83xxx_adc_nids;
4539 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4540 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4541 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4542 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4543
4544 spec->init = stac92hd83xxx_core_init;
4545 switch (codec->vendor_id) {
4546 case 0x111d7605:
4547 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4548 break;
4549 default:
4550 spec->num_pwrs--;
4551 spec->init++; /* switch to config #2 */
4552 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4553 }
4554
4555 spec->mixer = stac92hd83xxx_mixer;
4556 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4557 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4558 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4559 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4560 spec->dinput_mux = &stac92hd83xxx_dmux;
4561 spec->pin_nids = stac92hd83xxx_pin_nids;
4562 spec->board_config = snd_hda_check_board_config(codec,
4563 STAC_92HD83XXX_MODELS,
4564 stac92hd83xxx_models,
4565 stac92hd83xxx_cfg_tbl);
4566again:
4567 if (spec->board_config < 0) {
4568 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4569 " STAC92HD83XXX, using BIOS defaults\n");
4570 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004571 } else
4572 err = stac_save_pin_cfgs(codec,
4573 stac92hd83xxx_brd_tbl[spec->board_config]);
4574 if (err < 0) {
4575 stac92xx_free(codec);
4576 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004577 }
4578
4579 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4580 if (!err) {
4581 if (spec->board_config < 0) {
4582 printk(KERN_WARNING "hda_codec: No auto-config is "
4583 "available, default to model=ref\n");
4584 spec->board_config = STAC_92HD83XXX_REF;
4585 goto again;
4586 }
4587 err = -EINVAL;
4588 }
4589
4590 if (err < 0) {
4591 stac92xx_free(codec);
4592 return err;
4593 }
4594
4595 codec->patch_ops = stac92xx_patch_ops;
4596
4597 return 0;
4598}
4599
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004600#ifdef SND_HDA_NEEDS_RESUME
4601static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4602{
4603 struct sigmatel_spec *spec = codec->spec;
4604 int i;
4605 snd_hda_codec_write_cache(codec, codec->afg, 0,
4606 AC_VERB_SET_POWER_STATE, pwr);
4607
4608 msleep(1);
4609 for (i = 0; i < spec->num_adcs; i++) {
4610 snd_hda_codec_write_cache(codec,
4611 spec->adc_nids[i], 0,
4612 AC_VERB_SET_POWER_STATE, pwr);
4613 }
4614};
4615
4616static int stac92hd71xx_resume(struct hda_codec *codec)
4617{
4618 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4619 return stac92xx_resume(codec);
4620}
4621
4622static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4623{
4624 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
Matthew Ranostayc6798d22008-11-18 20:54:17 -05004625 return stac92xx_suspend(codec, state);
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004626};
4627
4628#endif
4629
4630static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4631 .build_controls = stac92xx_build_controls,
4632 .build_pcms = stac92xx_build_pcms,
4633 .init = stac92xx_init,
4634 .free = stac92xx_free,
4635 .unsol_event = stac92xx_unsol_event,
4636#ifdef SND_HDA_NEEDS_RESUME
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004637 .suspend = stac92hd71xx_suspend,
Matthew Ranostayc6798d22008-11-18 20:54:17 -05004638 .resume = stac92hd71xx_resume,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004639#endif
4640};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004641
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004642static struct hda_input_mux stac92hd71bxx_dmux = {
4643 .num_items = 4,
4644 .items = {
4645 { "Analog Inputs", 0x00 },
4646 { "Mixer", 0x01 },
4647 { "Digital Mic 1", 0x02 },
4648 { "Digital Mic 2", 0x03 },
4649 }
4650};
4651
Matthew Ranostaye035b842007-11-06 11:53:55 +01004652static int patch_stac92hd71bxx(struct hda_codec *codec)
4653{
4654 struct sigmatel_spec *spec;
4655 int err = 0;
4656
4657 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4658 if (spec == NULL)
4659 return -ENOMEM;
4660
4661 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004662 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004663 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004664 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004665 spec->pin_nids = stac92hd71bxx_pin_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004666 memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
4667 sizeof(stac92hd71bxx_dmux));
Matthew Ranostaye035b842007-11-06 11:53:55 +01004668 spec->board_config = snd_hda_check_board_config(codec,
4669 STAC_92HD71BXX_MODELS,
4670 stac92hd71bxx_models,
4671 stac92hd71bxx_cfg_tbl);
4672again:
4673 if (spec->board_config < 0) {
4674 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4675 " STAC92HD71BXX, using BIOS defaults\n");
4676 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004677 } else
4678 err = stac_save_pin_cfgs(codec,
4679 stac92hd71bxx_brd_tbl[spec->board_config]);
4680 if (err < 0) {
4681 stac92xx_free(codec);
4682 return err;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004683 }
4684
Takashi Iwai41c3b642008-11-18 10:45:15 +01004685 if (spec->board_config > STAC_92HD71BXX_REF) {
4686 /* GPIO0 = EAPD */
4687 spec->gpio_mask = 0x01;
4688 spec->gpio_dir = 0x01;
4689 spec->gpio_data = 0x01;
4690 }
4691
Matthew Ranostay541eee82007-12-14 12:08:04 +01004692 switch (codec->vendor_id) {
4693 case 0x111d76b6: /* 4 Port without Analog Mixer */
4694 case 0x111d76b7:
4695 case 0x111d76b4: /* 6 Port without Analog Mixer */
4696 case 0x111d76b5:
4697 spec->mixer = stac92hd71bxx_mixer;
4698 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004699 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004700 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004701 case 0x111d7608: /* 5 Port with Analog Mixer */
Takashi Iwai8e5f2622008-11-15 19:28:54 +01004702 switch (spec->board_config) {
4703 case STAC_HP_M4:
Matthew Ranostay72474be2008-10-09 09:32:17 -04004704 /* Enable VREF power saving on GPIO1 detect */
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01004705 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay72474be2008-10-09 09:32:17 -04004706 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4707 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004708 AC_VERB_SET_UNSOLICITED_ENABLE,
4709 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
4710 err = stac92xx_add_event(spec, codec->afg, 0x02);
4711 if (err < 0)
4712 return err;
Matthew Ranostay72474be2008-10-09 09:32:17 -04004713 spec->gpio_mask |= 0x02;
4714 break;
4715 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004716 if ((codec->revision_id & 0xf) == 0 ||
4717 (codec->revision_id & 0xf) == 1) {
4718#ifdef SND_HDA_NEEDS_RESUME
4719 codec->patch_ops = stac92hd71bxx_patch_ops;
4720#endif
4721 spec->stream_delay = 40; /* 40 milliseconds */
4722 }
4723
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004724 /* no output amps */
4725 spec->num_pwrs = 0;
4726 spec->mixer = stac92hd71bxx_analog_mixer;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004727 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004728
4729 /* disable VSW */
4730 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004731 stac_change_pin_config(codec, 0xf, 0x40f000f0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004732 break;
4733 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004734 if ((codec->revision_id & 0xf) == 1) {
4735#ifdef SND_HDA_NEEDS_RESUME
4736 codec->patch_ops = stac92hd71bxx_patch_ops;
4737#endif
4738 spec->stream_delay = 40; /* 40 milliseconds */
4739 }
4740
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004741 /* no output amps */
4742 spec->num_pwrs = 0;
4743 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004744 default:
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004745 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004746 spec->mixer = stac92hd71bxx_analog_mixer;
4747 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004748 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004749 }
4750
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004751 spec->aloopback_mask = 0x50;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004752 spec->aloopback_shift = 0;
4753
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004754 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004755 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004756 spec->mux_nids = stac92hd71bxx_mux_nids;
4757 spec->adc_nids = stac92hd71bxx_adc_nids;
4758 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004759 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004760 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004761 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004762
4763 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4764 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004765
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004766 switch (spec->board_config) {
4767 case STAC_HP_M4:
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004768 /* enable internal microphone */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004769 stac_change_pin_config(codec, 0x0e, 0x01813040);
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004770 stac92xx_auto_set_pinctl(codec, 0x0e,
4771 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05004772 /* fallthru */
4773 case STAC_DELL_M4_2:
4774 spec->num_dmics = 0;
4775 spec->num_smuxes = 0;
4776 spec->num_dmuxes = 0;
4777 break;
4778 case STAC_DELL_M4_1:
4779 case STAC_DELL_M4_3:
4780 spec->num_dmics = 1;
4781 spec->num_smuxes = 0;
4782 spec->num_dmuxes = 0;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004783 break;
4784 default:
4785 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4786 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4787 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4788 };
4789
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004790 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004791 spec->multiout.hp_nid = 0x11;
4792 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004793 if (spec->dinput_mux)
4794 spec->private_dimux.num_items +=
4795 spec->num_dmics -
4796 (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004797
4798 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4799 if (!err) {
4800 if (spec->board_config < 0) {
4801 printk(KERN_WARNING "hda_codec: No auto-config is "
4802 "available, default to model=ref\n");
4803 spec->board_config = STAC_92HD71BXX_REF;
4804 goto again;
4805 }
4806 err = -EINVAL;
4807 }
4808
4809 if (err < 0) {
4810 stac92xx_free(codec);
4811 return err;
4812 }
4813
Matthew Ranostaye035b842007-11-06 11:53:55 +01004814 return 0;
4815};
4816
Matt2f2f4252005-04-13 14:45:30 +02004817static int patch_stac922x(struct hda_codec *codec)
4818{
4819 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004820 int err;
Matt2f2f4252005-04-13 14:45:30 +02004821
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004822 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004823 if (spec == NULL)
4824 return -ENOMEM;
4825
4826 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004827 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004828 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004829 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4830 stac922x_models,
4831 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004832 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004833 spec->gpio_mask = spec->gpio_dir = 0x03;
4834 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004835 /* Intel Macs have all same PCI SSID, so we need to check
4836 * codec SSID to distinguish the exact models
4837 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004838 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004839 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004840
4841 case 0x106b0800:
4842 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004843 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004844 case 0x106b0600:
4845 case 0x106b0700:
4846 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004847 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004848 case 0x106b0e00:
4849 case 0x106b0f00:
4850 case 0x106b1600:
4851 case 0x106b1700:
4852 case 0x106b0200:
4853 case 0x106b1e00:
4854 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004855 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004856 case 0x106b1a00:
4857 case 0x00000100:
4858 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004859 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004860 case 0x106b0a00:
4861 case 0x106b2200:
4862 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004863 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004864 default:
4865 spec->board_config = STAC_INTEL_MAC_V3;
4866 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004867 }
4868 }
4869
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004870 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004871 if (spec->board_config < 0) {
4872 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4873 "using BIOS defaults\n");
4874 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004875 } else
4876 err = stac_save_pin_cfgs(codec,
4877 stac922x_brd_tbl[spec->board_config]);
4878 if (err < 0) {
4879 stac92xx_free(codec);
4880 return err;
Matt Porter403d1942005-11-29 15:00:51 +01004881 }
Matt2f2f4252005-04-13 14:45:30 +02004882
Matt2f2f4252005-04-13 14:45:30 +02004883 spec->adc_nids = stac922x_adc_nids;
4884 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004885 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004886 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004887 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004888 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004889
4890 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004891 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004892
4893 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004894
Matt Porter3cc08dc2006-01-23 15:27:49 +01004895 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004896 if (!err) {
4897 if (spec->board_config < 0) {
4898 printk(KERN_WARNING "hda_codec: No auto-config is "
4899 "available, default to model=ref\n");
4900 spec->board_config = STAC_D945_REF;
4901 goto again;
4902 }
4903 err = -EINVAL;
4904 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004905 if (err < 0) {
4906 stac92xx_free(codec);
4907 return err;
4908 }
4909
4910 codec->patch_ops = stac92xx_patch_ops;
4911
Takashi Iwai807a46362007-05-29 19:01:37 +02004912 /* Fix Mux capture level; max to 2 */
4913 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4914 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4915 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4916 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4917 (0 << AC_AMPCAP_MUTE_SHIFT));
4918
Matt Porter3cc08dc2006-01-23 15:27:49 +01004919 return 0;
4920}
4921
4922static int patch_stac927x(struct hda_codec *codec)
4923{
4924 struct sigmatel_spec *spec;
4925 int err;
4926
4927 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4928 if (spec == NULL)
4929 return -ENOMEM;
4930
4931 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004932 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004933 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004934 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4935 stac927x_models,
4936 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004937 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004938 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4939 if (spec->board_config < 0)
4940 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4941 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004942 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004943 } else
4944 err = stac_save_pin_cfgs(codec,
4945 stac927x_brd_tbl[spec->board_config]);
4946 if (err < 0) {
4947 stac92xx_free(codec);
4948 return err;
Matt Porter3cc08dc2006-01-23 15:27:49 +01004949 }
4950
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004951 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004952 spec->adc_nids = stac927x_adc_nids;
4953 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4954 spec->mux_nids = stac927x_mux_nids;
4955 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004956 spec->smux_nids = stac927x_smux_nids;
4957 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04004958 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004959 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004960 spec->multiout.dac_nids = spec->dac_nids;
4961
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004962 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004963 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004964 case STAC_D965_5ST:
4965 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004966 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004967 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004968 spec->num_dmics = 0;
4969
Tobin Davis93ed1502006-09-01 21:03:12 +02004970 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004971 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004972 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004973 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004974 switch (codec->subsystem_id) {
4975 case 0x10280209:
4976 case 0x1028022e:
4977 /* correct the device field to SPDIF out */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004978 stac_change_pin_config(codec, 0x21, 0x01442070);
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004979 break;
4980 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004981 /* configure the analog microphone on some laptops */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004982 stac_change_pin_config(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004983 /* correct the front output jack as a hp out */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004984 stac_change_pin_config(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004985 /* correct the front input jack as a mic */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004986 stac_change_pin_config(codec, 0x0e, 0x02a79130);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004987 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004988 case STAC_DELL_3ST:
4989 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004990 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004991 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004992 spec->dmic_nids = stac927x_dmic_nids;
4993 spec->num_dmics = STAC927X_NUM_DMICS;
4994
Tobin Davis93ed1502006-09-01 21:03:12 +02004995 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004996 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004997 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004998 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004999 break;
5000 default:
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04005001 if (spec->board_config > STAC_D965_REF) {
5002 /* GPIO0 High = Enable EAPD */
5003 spec->eapd_mask = spec->gpio_mask = 0x01;
5004 spec->gpio_dir = spec->gpio_data = 0x01;
5005 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005006 spec->num_dmics = 0;
5007
Tobin Davis81d3dbd2006-08-22 19:44:45 +02005008 spec->init = stac927x_core_init;
5009 spec->mixer = stac927x_mixer;
5010 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01005011
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005012 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005013 spec->aloopback_mask = 0x40;
5014 spec->aloopback_shift = 0;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05005015 spec->eapd_switch = 1;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005016
Matt Porter3cc08dc2006-01-23 15:27:49 +01005017 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005018 if (!err) {
5019 if (spec->board_config < 0) {
5020 printk(KERN_WARNING "hda_codec: No auto-config is "
5021 "available, default to model=ref\n");
5022 spec->board_config = STAC_D965_REF;
5023 goto again;
5024 }
5025 err = -EINVAL;
5026 }
Mattc7d4b2f2005-06-27 14:59:41 +02005027 if (err < 0) {
5028 stac92xx_free(codec);
5029 return err;
5030 }
Matt2f2f4252005-04-13 14:45:30 +02005031
5032 codec->patch_ops = stac92xx_patch_ops;
5033
Takashi Iwai52987652008-01-16 16:09:47 +01005034 /*
5035 * !!FIXME!!
5036 * The STAC927x seem to require fairly long delays for certain
5037 * command sequences. With too short delays (even if the answer
5038 * is set to RIRB properly), it results in the silence output
5039 * on some hardwares like Dell.
5040 *
5041 * The below flag enables the longer delay (see get_response
5042 * in hda_intel.c).
5043 */
5044 codec->bus->needs_damn_long_delay = 1;
5045
Matt2f2f4252005-04-13 14:45:30 +02005046 return 0;
5047}
5048
Matt Porterf3302a52006-07-31 12:49:34 +02005049static int patch_stac9205(struct hda_codec *codec)
5050{
5051 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02005052 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02005053
5054 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5055 if (spec == NULL)
5056 return -ENOMEM;
5057
5058 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02005059 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02005060 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005061 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
5062 stac9205_models,
5063 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005064 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02005065 if (spec->board_config < 0) {
5066 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
5067 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005068 } else
5069 err = stac_save_pin_cfgs(codec,
5070 stac9205_brd_tbl[spec->board_config]);
5071 if (err < 0) {
5072 stac92xx_free(codec);
5073 return err;
Matt Porterf3302a52006-07-31 12:49:34 +02005074 }
5075
Matthew Ranostay1cd22242008-07-18 18:20:52 +02005076 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02005077 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005078 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02005079 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01005080 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02005081 spec->smux_nids = stac9205_smux_nids;
5082 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02005083 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02005084 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005085 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01005086 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005087 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02005088
5089 spec->init = stac9205_core_init;
5090 spec->mixer = stac9205_mixer;
5091
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005092 spec->aloopback_mask = 0x40;
5093 spec->aloopback_shift = 0;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05005094 spec->eapd_switch = 1;
Matt Porterf3302a52006-07-31 12:49:34 +02005095 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02005096
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005097 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005098 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02005099 /* Enable SPDIF in/out */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005100 stac_change_pin_config(codec, 0x1f, 0x01441030);
5101 stac_change_pin_config(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01005102
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005103 /* Enable unsol response for GPIO4/Dock HP connection */
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01005104 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005105 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
5106 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04005107 AC_VERB_SET_UNSOLICITED_ENABLE,
5108 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
5109 err = stac92xx_add_event(spec, codec->afg, 0x01);
5110 if (err < 0)
5111 return err;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005112
5113 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005114 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005115 spec->gpio_mask = 0x1b;
5116 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01005117 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005118 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02005119 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005120 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005121 break;
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04005122 case STAC_9205_REF:
5123 /* SPDIF-In enabled */
5124 break;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005125 default:
5126 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005127 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005128 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005129 break;
5130 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02005131
Matt Porterf3302a52006-07-31 12:49:34 +02005132 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005133 if (!err) {
5134 if (spec->board_config < 0) {
5135 printk(KERN_WARNING "hda_codec: No auto-config is "
5136 "available, default to model=ref\n");
5137 spec->board_config = STAC_9205_REF;
5138 goto again;
5139 }
5140 err = -EINVAL;
5141 }
Matt Porterf3302a52006-07-31 12:49:34 +02005142 if (err < 0) {
5143 stac92xx_free(codec);
5144 return err;
5145 }
5146
5147 codec->patch_ops = stac92xx_patch_ops;
5148
5149 return 0;
5150}
5151
Matt2f2f4252005-04-13 14:45:30 +02005152/*
Guillaume Munch6d859062006-08-22 17:15:47 +02005153 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01005154 */
5155
Guillaume Munch99ccc562006-08-16 19:35:12 +02005156/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005157static hda_nid_t vaio_dacs[] = { 0x2 };
5158#define VAIO_HP_DAC 0x5
5159static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
5160static hda_nid_t vaio_mux_nids[] = { 0x15 };
5161
5162static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02005163 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01005164 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02005165 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005166 { "Mic Jack", 0x1 },
5167 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01005168 { "PCM", 0x3 },
5169 }
5170};
5171
5172static struct hda_verb vaio_init[] = {
5173 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005174 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01005175 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5176 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5177 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5178 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005179 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005180 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5181 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5182 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5183 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5185 {}
5186};
5187
Guillaume Munch6d859062006-08-22 17:15:47 +02005188static struct hda_verb vaio_ar_init[] = {
5189 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
5190 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5191 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5192 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5193/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
5194 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005195 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02005196 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5197 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5198/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
5199 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5200 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5201 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5202 {}
5203};
5204
Takashi Iwaidb064e52006-03-16 16:04:58 +01005205static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwai127e82e2008-11-14 14:03:33 +01005206 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
5207 HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
5208 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
5209 HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005210 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5211 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5212 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5213 {
5214 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5215 .name = "Capture Source",
5216 .count = 1,
5217 .info = stac92xx_mux_enum_info,
5218 .get = stac92xx_mux_enum_get,
5219 .put = stac92xx_mux_enum_put,
5220 },
5221 {}
5222};
5223
Guillaume Munch6d859062006-08-22 17:15:47 +02005224static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwai127e82e2008-11-14 14:03:33 +01005225 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
5226 HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
5227 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
5228 HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
Guillaume Munch6d859062006-08-22 17:15:47 +02005229 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5230 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5231 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5232 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
5233 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
5234 {
5235 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5236 .name = "Capture Source",
5237 .count = 1,
5238 .info = stac92xx_mux_enum_info,
5239 .get = stac92xx_mux_enum_get,
5240 .put = stac92xx_mux_enum_put,
5241 },
5242 {}
5243};
5244
5245static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01005246 .build_controls = stac92xx_build_controls,
5247 .build_pcms = stac92xx_build_pcms,
5248 .init = stac92xx_init,
5249 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005250#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01005251 .resume = stac92xx_resume,
5252#endif
5253};
5254
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005255static int stac9872_vaio_init(struct hda_codec *codec)
5256{
5257 int err;
5258
5259 err = stac92xx_init(codec);
5260 if (err < 0)
5261 return err;
5262 if (codec->patch_ops.unsol_event)
5263 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
5264 return 0;
5265}
5266
5267static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
5268{
Jiang Zhe40c1d302007-11-12 13:05:16 +01005269 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005270 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5271 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5272 } else {
5273 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5274 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5275 }
5276}
5277
5278static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
5279{
5280 switch (res >> 26) {
5281 case STAC_HP_EVENT:
5282 stac9872_vaio_hp_detect(codec, res);
5283 break;
5284 }
5285}
5286
5287static struct hda_codec_ops stac9872_vaio_patch_ops = {
5288 .build_controls = stac92xx_build_controls,
5289 .build_pcms = stac92xx_build_pcms,
5290 .init = stac9872_vaio_init,
5291 .free = stac92xx_free,
5292 .unsol_event = stac9872_vaio_unsol_event,
5293#ifdef CONFIG_PM
5294 .resume = stac92xx_resume,
5295#endif
5296};
5297
Guillaume Munch6d859062006-08-22 17:15:47 +02005298enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
5299 CXD9872RD_VAIO,
5300 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
5301 STAC9872AK_VAIO,
5302 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
5303 STAC9872K_VAIO,
5304 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005305 CXD9872AKD_VAIO,
5306 STAC_9872_MODELS,
5307};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005308
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005309static const char *stac9872_models[STAC_9872_MODELS] = {
5310 [CXD9872RD_VAIO] = "vaio",
5311 [CXD9872AKD_VAIO] = "vaio-ar",
5312};
5313
5314static struct snd_pci_quirk stac9872_cfg_tbl[] = {
5315 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
5316 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
5317 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01005318 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005319 {}
5320};
5321
Guillaume Munch6d859062006-08-22 17:15:47 +02005322static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01005323{
5324 struct sigmatel_spec *spec;
5325 int board_config;
5326
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005327 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
5328 stac9872_models,
5329 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01005330 if (board_config < 0)
5331 /* unknown config, let generic-parser do its job... */
5332 return snd_hda_parse_generic_codec(codec);
5333
5334 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5335 if (spec == NULL)
5336 return -ENOMEM;
5337
5338 codec->spec = spec;
5339 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02005340 case CXD9872RD_VAIO:
5341 case STAC9872AK_VAIO:
5342 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01005343 spec->mixer = vaio_mixer;
5344 spec->init = vaio_init;
5345 spec->multiout.max_channels = 2;
5346 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5347 spec->multiout.dac_nids = vaio_dacs;
5348 spec->multiout.hp_nid = VAIO_HP_DAC;
5349 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
5350 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005351 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005352 spec->input_mux = &vaio_mux;
5353 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005354 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005355 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02005356
5357 case CXD9872AKD_VAIO:
5358 spec->mixer = vaio_ar_mixer;
5359 spec->init = vaio_ar_init;
5360 spec->multiout.max_channels = 2;
5361 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5362 spec->multiout.dac_nids = vaio_dacs;
5363 spec->multiout.hp_nid = VAIO_HP_DAC;
5364 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005365 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02005366 spec->adc_nids = vaio_adcs;
5367 spec->input_mux = &vaio_mux;
5368 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005369 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02005370 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005371 }
5372
Takashi Iwaidb064e52006-03-16 16:04:58 +01005373 return 0;
5374}
5375
5376
5377/*
Matt2f2f4252005-04-13 14:45:30 +02005378 * patch entries
5379 */
5380struct hda_codec_preset snd_hda_preset_sigmatel[] = {
5381 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
5382 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
5383 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
5384 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
5385 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
5386 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
5387 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02005388 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
5389 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
5390 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
5391 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
5392 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
5393 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01005394 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
5395 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
5396 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
5397 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
5398 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
5399 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
5400 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
5401 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
5402 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
5403 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01005404 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
5405 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
5406 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
5407 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
5408 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
5409 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02005410 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
5411 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02005412 /* The following does not take into account .id=0x83847661 when subsys =
5413 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
5414 * currently not fully supported.
5415 */
5416 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
5417 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
5418 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02005419 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
5420 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
5421 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
5422 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
5423 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
5424 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
5425 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
5426 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005427 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005428 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
5429 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005430 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01005431 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
5432 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005433 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01005434 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5435 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5436 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5437 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5438 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5439 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5440 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
5441 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02005442 {} /* terminator */
5443};