blob: c24d22fddd09912c6fb90d0e56aaa491d545c14b [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 Ranostay74aeaab2008-10-25 01:06:04 -040039#define STAC_INSERT_EVENT 0x10
Matthew Ranostaya64135a2008-01-10 16:55:06 +010040#define STAC_PWR_EVENT 0x20
41#define STAC_HP_EVENT 0x30
Matthew Ranostay72474be2008-10-09 09:32:17 -040042#define STAC_VREF_EVENT 0x40
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 Ranostaye1f0d662007-12-13 17:47:21 +010073 STAC_92HD73XX_MODELS
74};
75
76enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020077 STAC_92HD83XXX_REF,
78 STAC_92HD83XXX_MODELS
79};
80
81enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010082 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010083 STAC_DELL_M4_1,
84 STAC_DELL_M4_2,
Matthew Ranostay6a14f582008-09-12 12:02:30 -040085 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010086 STAC_92HD71BXX_MODELS
87};
88
89enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010090 STAC_925x_REF,
91 STAC_M2_2,
92 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020093 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010094 STAC_925x_MODELS
95};
96
97enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010098 STAC_D945_REF,
99 STAC_D945GTP3,
100 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200101 STAC_INTEL_MAC_V1,
102 STAC_INTEL_MAC_V2,
103 STAC_INTEL_MAC_V3,
104 STAC_INTEL_MAC_V4,
105 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800106 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
107 * is given, one of the above models will be
108 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200109 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100110 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100111 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100112 STAC_MACBOOK_PRO_V1,
113 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200114 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200115 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300116 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200117 STAC_922X_DELL_D81,
118 STAC_922X_DELL_D82,
119 STAC_922X_DELL_M81,
120 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100121 STAC_922X_MODELS
122};
123
124enum {
125 STAC_D965_REF,
126 STAC_D965_3ST,
127 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200128 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100129 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100130 STAC_927X_MODELS
131};
Matt Porter403d1942005-11-29 15:00:51 +0100132
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400133struct sigmatel_event {
134 hda_nid_t nid;
135 int data;
136};
137
138struct sigmatel_jack {
139 hda_nid_t nid;
140 int type;
141 struct snd_jack *jack;
142};
143
Matt2f2f4252005-04-13 14:45:30 +0200144struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100145 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200146 unsigned int num_mixers;
147
Matt Porter403d1942005-11-29 15:00:51 +0100148 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200149 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100150 unsigned int line_switch: 1;
151 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100152 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100153 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400154 unsigned int spdif_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200155
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100156 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200157 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100158 unsigned int gpio_mask;
159 unsigned int gpio_dir;
160 unsigned int gpio_data;
161 unsigned int gpio_mute;
162
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200163 /* stream */
164 unsigned int stream_delay;
165
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100166 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100167 unsigned char aloopback_mask;
168 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200169
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100170 /* power management */
171 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200172 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100173 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100174 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100175
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400176 /* jack detection */
177 struct snd_array jacks;
178
179 /* events */
180 struct snd_array events;
181
Matt2f2f4252005-04-13 14:45:30 +0200182 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100183 struct hda_input_mux *mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400184 struct hda_input_mux *amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100185 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200186 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100187 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200188
189 /* capture */
190 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200191 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200192 hda_nid_t *mux_nids;
193 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200194 hda_nid_t *dmic_nids;
195 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100196 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100197 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200198 hda_nid_t *smux_nids;
199 unsigned int num_smuxes;
Matthew Ranostay65973632008-09-16 10:39:37 -0400200 const char **spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200201
Mattdabbed62005-06-14 10:19:34 +0200202 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100203 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200204 hda_nid_t anabeep_nid;
205 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200206
Matt2f2f4252005-04-13 14:45:30 +0200207 /* pin widgets */
208 hda_nid_t *pin_nids;
209 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200210 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200211 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200212
213 /* codec specific stuff */
214 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100215 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200216
217 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200218 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100219 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200220 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100221 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200222 struct hda_input_mux *sinput_mux;
223 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400224 unsigned int cur_amux;
225 hda_nid_t *amp_nids;
226 unsigned int num_amps;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200227 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200228
Matt Porter403d1942005-11-29 15:00:51 +0100229 /* i/o switches */
230 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200231 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200232 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200233 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200234
Mattc7d4b2f2005-06-27 14:59:41 +0200235 struct hda_pcm pcm_rec[2]; /* PCM information */
236
237 /* dynamic controls and input_mux */
238 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200239 struct snd_array kctls;
Matt Porter8b657272006-10-26 17:12:59 +0200240 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200241 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200242 struct hda_input_mux private_smux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400243 struct hda_input_mux private_amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100244 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200245};
246
247static hda_nid_t stac9200_adc_nids[1] = {
248 0x03,
249};
250
251static hda_nid_t stac9200_mux_nids[1] = {
252 0x0c,
253};
254
255static hda_nid_t stac9200_dac_nids[1] = {
256 0x02,
257};
258
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100259static hda_nid_t stac92hd73xx_pwr_nids[8] = {
260 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
261 0x0f, 0x10, 0x11
262};
263
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400264static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
265 0x26, 0,
266};
267
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100268static hda_nid_t stac92hd73xx_adc_nids[2] = {
269 0x1a, 0x1b
270};
271
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400272#define DELL_M6_AMP 2
273static hda_nid_t stac92hd73xx_amp_nids[3] = {
274 0x0b, 0x0c, 0x0e
Matthew Ranostay89385032008-09-11 09:49:39 -0400275};
276
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100277#define STAC92HD73XX_NUM_DMICS 2
278static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
279 0x13, 0x14, 0
280};
281
282#define STAC92HD73_DAC_COUNT 5
283static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
284 0x15, 0x16, 0x17, 0x18, 0x19,
285};
286
287static hda_nid_t stac92hd73xx_mux_nids[4] = {
288 0x28, 0x29, 0x2a, 0x2b,
289};
290
291static hda_nid_t stac92hd73xx_dmux_nids[2] = {
292 0x20, 0x21,
293};
294
Matthew Ranostayd9737752008-09-07 12:03:41 +0200295static hda_nid_t stac92hd73xx_smux_nids[2] = {
296 0x22, 0x23,
297};
298
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200299#define STAC92HD83XXX_NUM_DMICS 2
300static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
301 0x11, 0x12, 0
302};
303
304#define STAC92HD81_DAC_COUNT 2
305#define STAC92HD83_DAC_COUNT 3
306static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
307 0x13, 0x14, 0x22,
308};
309
310static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
311 0x17, 0x18,
312};
313
314static hda_nid_t stac92hd83xxx_adc_nids[2] = {
315 0x15, 0x16,
316};
317
318static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
319 0xa, 0xb, 0xd, 0xe,
320};
321
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400322static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
323 0x1e, 0,
324};
325
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200326static unsigned int stac92hd83xxx_pwr_mapping[4] = {
327 0x03, 0x0c, 0x10, 0x40,
328};
329
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100330static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
331 0x0a, 0x0d, 0x0f
332};
333
Matthew Ranostaye035b842007-11-06 11:53:55 +0100334static hda_nid_t stac92hd71bxx_adc_nids[2] = {
335 0x12, 0x13,
336};
337
338static hda_nid_t stac92hd71bxx_mux_nids[2] = {
339 0x1a, 0x1b
340};
341
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400342static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
343 0x1c, 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100344};
345
Matthew Ranostayd9737752008-09-07 12:03:41 +0200346static hda_nid_t stac92hd71bxx_smux_nids[2] = {
347 0x24, 0x25,
348};
349
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100350static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100351 0x10, /*0x11, */
352};
353
354#define STAC92HD71BXX_NUM_DMICS 2
355static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
356 0x18, 0x19, 0
357};
358
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400359static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
360 0x22, 0
361};
362
Tobin Davis8e21c342007-01-08 11:04:17 +0100363static hda_nid_t stac925x_adc_nids[1] = {
364 0x03,
365};
366
367static hda_nid_t stac925x_mux_nids[1] = {
368 0x0f,
369};
370
371static hda_nid_t stac925x_dac_nids[1] = {
372 0x02,
373};
374
Takashi Iwaif6e98522007-10-16 14:27:04 +0200375#define STAC925X_NUM_DMICS 1
376static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
377 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200378};
379
Takashi Iwai1697055e2007-12-18 18:05:52 +0100380static hda_nid_t stac925x_dmux_nids[1] = {
381 0x14,
382};
383
Matt2f2f4252005-04-13 14:45:30 +0200384static hda_nid_t stac922x_adc_nids[2] = {
385 0x06, 0x07,
386};
387
388static hda_nid_t stac922x_mux_nids[2] = {
389 0x12, 0x13,
390};
391
Matt Porter3cc08dc2006-01-23 15:27:49 +0100392static hda_nid_t stac927x_adc_nids[3] = {
393 0x07, 0x08, 0x09
394};
395
396static hda_nid_t stac927x_mux_nids[3] = {
397 0x15, 0x16, 0x17
398};
399
Matthew Ranostayd9737752008-09-07 12:03:41 +0200400static hda_nid_t stac927x_smux_nids[1] = {
401 0x21,
402};
403
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100404static hda_nid_t stac927x_dac_nids[6] = {
405 0x02, 0x03, 0x04, 0x05, 0x06, 0
406};
407
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100408static hda_nid_t stac927x_dmux_nids[1] = {
409 0x1b,
410};
411
Matthew Ranostay7f168592007-10-18 17:38:17 +0200412#define STAC927X_NUM_DMICS 2
413static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
414 0x13, 0x14, 0
415};
416
Matthew Ranostay65973632008-09-16 10:39:37 -0400417static const char *stac927x_spdif_labels[5] = {
418 "Digital Playback", "ADAT", "Analog Mux 1",
419 "Analog Mux 2", "Analog Mux 3"
420};
421
Matt Porterf3302a52006-07-31 12:49:34 +0200422static hda_nid_t stac9205_adc_nids[2] = {
423 0x12, 0x13
424};
425
426static hda_nid_t stac9205_mux_nids[2] = {
427 0x19, 0x1a
428};
429
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100430static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100431 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100432};
433
Matthew Ranostayd9737752008-09-07 12:03:41 +0200434static hda_nid_t stac9205_smux_nids[1] = {
435 0x21,
436};
437
Takashi Iwaif6e98522007-10-16 14:27:04 +0200438#define STAC9205_NUM_DMICS 2
439static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
440 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200441};
442
Mattc7d4b2f2005-06-27 14:59:41 +0200443static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200444 0x08, 0x09, 0x0d, 0x0e,
445 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200446};
447
Tobin Davis8e21c342007-01-08 11:04:17 +0100448static hda_nid_t stac925x_pin_nids[8] = {
449 0x07, 0x08, 0x0a, 0x0b,
450 0x0c, 0x0d, 0x10, 0x11,
451};
452
Matt2f2f4252005-04-13 14:45:30 +0200453static hda_nid_t stac922x_pin_nids[10] = {
454 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
455 0x0f, 0x10, 0x11, 0x15, 0x1b,
456};
457
Matthew Ranostaya7662642008-02-21 07:51:14 +0100458static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100459 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
460 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200461 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100462};
463
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200464static hda_nid_t stac92hd83xxx_pin_nids[14] = {
465 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
466 0x0f, 0x10, 0x11, 0x12, 0x13,
467 0x1d, 0x1e, 0x1f, 0x20
468};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400469static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100470 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
471 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400472 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100473};
474
Matt Porter3cc08dc2006-01-23 15:27:49 +0100475static hda_nid_t stac927x_pin_nids[14] = {
476 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
477 0x0f, 0x10, 0x11, 0x12, 0x13,
478 0x14, 0x21, 0x22, 0x23,
479};
480
Matt Porterf3302a52006-07-31 12:49:34 +0200481static hda_nid_t stac9205_pin_nids[12] = {
482 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
483 0x0f, 0x14, 0x16, 0x17, 0x18,
484 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200485};
486
Matthew Ranostay89385032008-09-11 09:49:39 -0400487#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
488
489static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_value *ucontrol)
491{
492 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
493 struct sigmatel_spec *spec = codec->spec;
494 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
495
496 kcontrol->private_value ^= get_amp_nid(kcontrol);
497 kcontrol->private_value |= nid;
498
499 return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
500}
501
502static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
503 struct snd_ctl_elem_value *ucontrol)
504{
505 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
506 struct sigmatel_spec *spec = codec->spec;
507 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
508
509 kcontrol->private_value ^= get_amp_nid(kcontrol);
510 kcontrol->private_value |= nid;
511
512 return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
513}
514
Matt Porter8b657272006-10-26 17:12:59 +0200515static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
516 struct snd_ctl_elem_info *uinfo)
517{
518 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
519 struct sigmatel_spec *spec = codec->spec;
520 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
521}
522
523static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
524 struct snd_ctl_elem_value *ucontrol)
525{
526 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
527 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100528 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200529
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100530 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200531 return 0;
532}
533
534static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
535 struct snd_ctl_elem_value *ucontrol)
536{
537 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
538 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100539 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200540
541 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100542 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200543}
544
Matthew Ranostayd9737752008-09-07 12:03:41 +0200545static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
546 struct snd_ctl_elem_info *uinfo)
547{
548 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
549 struct sigmatel_spec *spec = codec->spec;
550 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
551}
552
553static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
554 struct snd_ctl_elem_value *ucontrol)
555{
556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 struct sigmatel_spec *spec = codec->spec;
558 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
559
560 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
561 return 0;
562}
563
564static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
565 struct snd_ctl_elem_value *ucontrol)
566{
567 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
568 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400569 struct hda_input_mux *smux = &spec->private_smux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200570 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400571 int err, val;
572 hda_nid_t nid;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200573
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400574 err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200575 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400576 if (err < 0)
577 return err;
578
579 if (spec->spdif_mute) {
580 if (smux_idx == 0)
581 nid = spec->multiout.dig_out_nid;
582 else
583 nid = codec->slave_dig_outs[smux_idx - 1];
584 if (spec->cur_smux[smux_idx] == smux->num_items - 1)
585 val = AMP_OUT_MUTE;
586 if (smux_idx == 0)
587 nid = spec->multiout.dig_out_nid;
588 else
589 nid = codec->slave_dig_outs[smux_idx - 1];
590 /* 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 Ranostay20f5f952008-09-01 08:17:56 +0200795 /* set master volume to max value without distortion
796 * and direct control */
797 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100798 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100799 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
800 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100801 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
802 /* setup adcs to point to mixer */
803 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
804 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
805 /* setup import muxs */
806 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
807 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
808 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
809 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
810 {}
811};
812
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100813static struct hda_verb stac92hd73xx_8ch_core_init[] = {
814 /* set master volume and direct control */
815 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
816 /* setup audio connections */
817 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
818 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
819 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
820 /* connect hp ports to dac3 */
821 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
822 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
823 /* setup adcs to point to mixer */
824 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
825 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100826 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
827 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
828 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
829 /* setup import muxs */
830 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
831 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
832 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
833 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
834 {}
835};
836
837static struct hda_verb stac92hd73xx_10ch_core_init[] = {
838 /* set master volume and direct control */
839 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
840 /* setup audio connections */
841 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
842 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
843 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
844 /* dac3 is connected to import3 mux */
845 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
846 /* connect hp ports to dac4 */
847 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
848 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
849 /* setup adcs to point to mixer */
850 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
851 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100852 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
853 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
854 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
855 /* setup import muxs */
856 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
857 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
858 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
859 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
860 {}
861};
862
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200863static struct hda_verb stac92hd83xxx_core_init[] = {
864 /* start of config #1 */
865 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
866
867 /* start of config #2 */
868 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
869 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
870 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
871
872 /* power state controls amps */
873 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
874};
875
Matthew Ranostaye035b842007-11-06 11:53:55 +0100876static struct hda_verb stac92hd71bxx_core_init[] = {
877 /* set master volume and direct control */
878 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
879 /* connect headphone jack to dac1 */
880 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100881 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
882 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
883 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
884 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100885};
886
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400887#define HD_DISABLE_PORTF 2
Matthew Ranostay541eee82007-12-14 12:08:04 +0100888static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200889 /* start of config #1 */
890
891 /* connect port 0f to audio mixer */
892 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200893 /* unmute right and left channels for node 0x0f */
894 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
895 /* start of config #2 */
896
Matthew Ranostay541eee82007-12-14 12:08:04 +0100897 /* set master volume and direct control */
898 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
899 /* connect headphone jack to dac1 */
900 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200901 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100902 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
903 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100904 {}
905};
906
Tobin Davis8e21c342007-01-08 11:04:17 +0100907static struct hda_verb stac925x_core_init[] = {
908 /* set dac0mux for dac converter */
909 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
910 {}
911};
912
Mattc7d4b2f2005-06-27 14:59:41 +0200913static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200914 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200915 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200916 {}
917};
918
Tobin Davis93ed1502006-09-01 21:03:12 +0200919static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200920 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200921 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200922 /* unmute node 0x1b */
923 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
924 /* select node 0x03 as DAC */
925 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
926 {}
927};
928
Matt Porter3cc08dc2006-01-23 15:27:49 +0100929static struct hda_verb stac927x_core_init[] = {
930 /* set master volume and direct control */
931 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200932 /* enable analog pc beep path */
933 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100934 {}
935};
936
Matt Porterf3302a52006-07-31 12:49:34 +0200937static struct hda_verb stac9205_core_init[] = {
938 /* set master volume and direct control */
939 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200940 /* enable analog pc beep path */
941 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200942 {}
943};
944
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100945#define STAC_MONO_MUX \
946 { \
947 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
948 .name = "Mono Mux", \
949 .count = 1, \
950 .info = stac92xx_mono_mux_enum_info, \
951 .get = stac92xx_mono_mux_enum_get, \
952 .put = stac92xx_mono_mux_enum_put, \
953 }
954
Matthew Ranostay89385032008-09-11 09:49:39 -0400955#define STAC_AMP_MUX \
956 { \
957 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
958 .name = "Amp Selector Capture Switch", \
959 .count = 1, \
960 .info = stac92xx_amp_mux_enum_info, \
961 .get = stac92xx_amp_mux_enum_get, \
962 .put = stac92xx_amp_mux_enum_put, \
963 }
964
965#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
966 { \
967 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
968 .name = xname, \
969 .index = 0, \
970 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
971 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
972 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
973 .info = stac92xx_amp_volume_info, \
974 .get = stac92xx_amp_volume_get, \
975 .put = stac92xx_amp_volume_put, \
976 .tlv = { .c = snd_hda_mixer_amp_tlv }, \
977 .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
978 }
979
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200980#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200981 { \
982 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
983 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200984 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200985 .info = stac92xx_mux_enum_info, \
986 .get = stac92xx_mux_enum_get, \
987 .put = stac92xx_mux_enum_put, \
988 }
989
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100990#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200991 { \
992 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
993 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100994 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200995 .info = stac92xx_aloopback_info, \
996 .get = stac92xx_aloopback_get, \
997 .put = stac92xx_aloopback_put, \
998 .private_value = verb_read | (verb_write << 16), \
999 }
1000
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001001static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +02001002 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
1003 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001004 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +02001005 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
1006 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +02001007 { } /* end */
1008};
1009
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001010#define DELL_M6_MIXER 6
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001011static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001012 /* start of config #1 */
1013 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1014 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1015
1016 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1017 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1018
1019 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1020 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1021
1022 /* start of config #2 */
1023 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1024 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1025
1026 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1027 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1028
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001029 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
1030
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001031 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1032 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1033
1034 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1035 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1036
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001037 { } /* end */
1038};
1039
1040static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001041 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1042
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001043 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1044 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1045
1046 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1047 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1048
1049 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1050 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1051
1052 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1053 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1054
1055 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1056 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1057
1058 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1059 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1060
1061 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1062 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1063 { } /* end */
1064};
1065
1066static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001067 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1068
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001069 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1070 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1071
1072 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1073 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1074
1075 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1076 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1077
1078 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1079 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1080
1081 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1082 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1083
1084 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1085 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1086
1087 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1088 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1089 { } /* end */
1090};
1091
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001092
1093static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
1094 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
1095 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
1096
1097 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
1098 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
1099
1100 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
1101 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
1102
1103 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
1104 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
1105
1106 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
1107 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
1108
1109 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
1110 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
1111
1112 /*
1113 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
1114 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
1115 */
1116 { } /* end */
1117};
1118
Matthew Ranostay541eee82007-12-14 12:08:04 +01001119static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001120 STAC_INPUT_SOURCE(2),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001121 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001122
Matthew Ranostay9b359472007-11-07 13:03:12 +01001123 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1124 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +01001125
1126 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1127 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001128 /* analog pc-beep replaced with digital beep support */
1129 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001130 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
1131 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001132 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001133
Matthew Ranostay687cb982008-10-11 13:52:43 -04001134 HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
1135 HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001136
Matthew Ranostay687cb982008-10-11 13:52:43 -04001137 HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
1138 HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001139
1140 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
1141 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
1142
1143 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
1144 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001145 { } /* end */
1146};
1147
Matthew Ranostay541eee82007-12-14 12:08:04 +01001148static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +01001149 STAC_INPUT_SOURCE(2),
1150 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
1151
Matthew Ranostay541eee82007-12-14 12:08:04 +01001152 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1153 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001154
1155 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1156 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001157 { } /* end */
1158};
1159
Tobin Davis8e21c342007-01-08 11:04:17 +01001160static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001161 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001162 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001163 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001164 { } /* end */
1165};
1166
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001167static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001168 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001169 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001170
1171 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1172 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001173
1174 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1175 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001176 { } /* end */
1177};
1178
1179/* This needs to be generated dynamically based on sequence */
1180static struct snd_kcontrol_new stac922x_mixer[] = {
1181 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001182 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1183 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001184
1185 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1186 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001187 { } /* end */
1188};
1189
1190
1191static struct snd_kcontrol_new stac927x_mixer[] = {
1192 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001193 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001194
1195 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1196 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001197
1198 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1199 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001200
1201 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1202 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001203 { } /* end */
1204};
1205
Takashi Iwai1697055e2007-12-18 18:05:52 +01001206static struct snd_kcontrol_new stac_dmux_mixer = {
1207 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1208 .name = "Digital Input Source",
1209 /* count set later */
1210 .info = stac92xx_dmux_enum_info,
1211 .get = stac92xx_dmux_enum_get,
1212 .put = stac92xx_dmux_enum_put,
1213};
1214
Matthew Ranostayd9737752008-09-07 12:03:41 +02001215static struct snd_kcontrol_new stac_smux_mixer = {
1216 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001217 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001218 /* count set later */
1219 .info = stac92xx_smux_enum_info,
1220 .get = stac92xx_smux_enum_get,
1221 .put = stac92xx_smux_enum_put,
1222};
1223
Takashi Iwai2134ea42008-01-10 16:53:55 +01001224static const char *slave_vols[] = {
1225 "Front Playback Volume",
1226 "Surround Playback Volume",
1227 "Center Playback Volume",
1228 "LFE Playback Volume",
1229 "Side Playback Volume",
1230 "Headphone Playback Volume",
1231 "Headphone Playback Volume",
1232 "Speaker Playback Volume",
1233 "External Speaker Playback Volume",
1234 "Speaker2 Playback Volume",
1235 NULL
1236};
1237
1238static const char *slave_sws[] = {
1239 "Front Playback Switch",
1240 "Surround Playback Switch",
1241 "Center Playback Switch",
1242 "LFE Playback Switch",
1243 "Side Playback Switch",
1244 "Headphone Playback Switch",
1245 "Headphone Playback Switch",
1246 "Speaker Playback Switch",
1247 "External Speaker Playback Switch",
1248 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001249 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001250 NULL
1251};
1252
Takashi Iwai603c4012008-07-30 15:01:44 +02001253static void stac92xx_free_kctls(struct hda_codec *codec);
1254
Matt2f2f4252005-04-13 14:45:30 +02001255static int stac92xx_build_controls(struct hda_codec *codec)
1256{
1257 struct sigmatel_spec *spec = codec->spec;
1258 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001259 int i;
Matt2f2f4252005-04-13 14:45:30 +02001260
1261 err = snd_hda_add_new_ctls(codec, spec->mixer);
1262 if (err < 0)
1263 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001264
1265 for (i = 0; i < spec->num_mixers; i++) {
1266 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1267 if (err < 0)
1268 return err;
1269 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001270 if (spec->num_dmuxes > 0) {
1271 stac_dmux_mixer.count = spec->num_dmuxes;
Takashi Iwaid13bd412008-07-30 15:01:45 +02001272 err = snd_hda_ctl_add(codec,
Takashi Iwai1697055e2007-12-18 18:05:52 +01001273 snd_ctl_new1(&stac_dmux_mixer, codec));
1274 if (err < 0)
1275 return err;
1276 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001277 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001278 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1279 struct hda_input_mux *smux = &spec->private_smux;
1280 /* check for mute support on SPDIF out */
1281 if (wcaps & AC_WCAP_OUT_AMP) {
1282 smux->items[smux->num_items].label = "Off";
1283 smux->items[smux->num_items].index = 0;
1284 smux->num_items++;
1285 spec->spdif_mute = 1;
1286 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001287 stac_smux_mixer.count = spec->num_smuxes;
1288 err = snd_ctl_add(codec->bus->card,
1289 snd_ctl_new1(&stac_smux_mixer, codec));
1290 if (err < 0)
1291 return err;
1292 }
Mattc7d4b2f2005-06-27 14:59:41 +02001293
Mattdabbed62005-06-14 10:19:34 +02001294 if (spec->multiout.dig_out_nid) {
1295 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1296 if (err < 0)
1297 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001298 err = snd_hda_create_spdif_share_sw(codec,
1299 &spec->multiout);
1300 if (err < 0)
1301 return err;
1302 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001303 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04001304 if (spec->dig_in_nid && (!spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001305 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1306 if (err < 0)
1307 return err;
1308 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001309
1310 /* if we have no master control, let's create it */
1311 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001312 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001313 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001314 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001315 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001316 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001317 if (err < 0)
1318 return err;
1319 }
1320 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1321 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1322 NULL, slave_sws);
1323 if (err < 0)
1324 return err;
1325 }
1326
Takashi Iwai603c4012008-07-30 15:01:44 +02001327 stac92xx_free_kctls(codec); /* no longer needed */
Mattdabbed62005-06-14 10:19:34 +02001328 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001329}
1330
Matt Porter403d1942005-11-29 15:00:51 +01001331static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001332 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001333 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1334};
1335
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001336/*
1337 STAC 9200 pin configs for
1338 102801A8
1339 102801DE
1340 102801E8
1341*/
1342static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001343 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1344 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001345};
1346
1347/*
1348 STAC 9200 pin configs for
1349 102801C0
1350 102801C1
1351*/
1352static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001353 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1354 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001355};
1356
1357/*
1358 STAC 9200 pin configs for
1359 102801C4 (Dell Dimension E310)
1360 102801C5
1361 102801C7
1362 102801D9
1363 102801DA
1364 102801E3
1365*/
1366static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001367 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1368 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001369};
1370
1371
1372/*
1373 STAC 9200-32 pin configs for
1374 102801B5 (Dell Inspiron 630m)
1375 102801D8 (Dell Inspiron 640m)
1376*/
1377static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001378 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1379 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001380};
1381
1382/*
1383 STAC 9200-32 pin configs for
1384 102801C2 (Dell Latitude D620)
1385 102801C8
1386 102801CC (Dell Latitude D820)
1387 102801D4
1388 102801D6
1389*/
1390static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001391 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1392 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001393};
1394
1395/*
1396 STAC 9200-32 pin configs for
1397 102801CE (Dell XPS M1710)
1398 102801CF (Dell Precision M90)
1399*/
1400static unsigned int dell9200_m23_pin_configs[8] = {
1401 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1402 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1403};
1404
1405/*
1406 STAC 9200-32 pin configs for
1407 102801C9
1408 102801CA
1409 102801CB (Dell Latitude 120L)
1410 102801D3
1411*/
1412static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001413 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1414 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001415};
1416
1417/*
1418 STAC 9200-32 pin configs for
1419 102801BD (Dell Inspiron E1505n)
1420 102801EE
1421 102801EF
1422*/
1423static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001424 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1425 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001426};
1427
1428/*
1429 STAC 9200-32 pin configs for
1430 102801F5 (Dell Inspiron 1501)
1431 102801F6
1432*/
1433static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001434 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1435 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001436};
1437
1438/*
1439 STAC 9200-32
1440 102801CD (Dell Inspiron E1705/9400)
1441*/
1442static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001443 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1444 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001445};
1446
Tobin Davisbf277782008-02-03 20:31:47 +01001447static unsigned int oqo9200_pin_configs[8] = {
1448 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1449 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1450};
1451
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001452
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001453static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1454 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001455 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001456 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1457 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1458 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1459 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1460 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1461 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1462 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1463 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1464 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1465 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001466 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001467};
1468
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001469static const char *stac9200_models[STAC_9200_MODELS] = {
1470 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001471 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001472 [STAC_9200_DELL_D21] = "dell-d21",
1473 [STAC_9200_DELL_D22] = "dell-d22",
1474 [STAC_9200_DELL_D23] = "dell-d23",
1475 [STAC_9200_DELL_M21] = "dell-m21",
1476 [STAC_9200_DELL_M22] = "dell-m22",
1477 [STAC_9200_DELL_M23] = "dell-m23",
1478 [STAC_9200_DELL_M24] = "dell-m24",
1479 [STAC_9200_DELL_M25] = "dell-m25",
1480 [STAC_9200_DELL_M26] = "dell-m26",
1481 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001482 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001483 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001484};
1485
1486static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1487 /* SigmaTel reference board */
1488 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1489 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001490 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001491 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1492 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001493 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001494 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1495 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1496 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1497 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1498 "unknown Dell", STAC_9200_DELL_D22),
1499 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1500 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001501 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001502 "Dell Latitude D620", STAC_9200_DELL_M22),
1503 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1504 "unknown Dell", STAC_9200_DELL_D23),
1505 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1506 "unknown Dell", STAC_9200_DELL_D23),
1507 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1508 "unknown Dell", STAC_9200_DELL_M22),
1509 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1510 "unknown Dell", STAC_9200_DELL_M24),
1511 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1512 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001513 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001514 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001515 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001516 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001517 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001518 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001519 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001520 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001521 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001522 "Dell Precision M90", STAC_9200_DELL_M23),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1524 "unknown Dell", STAC_9200_DELL_M22),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1526 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001527 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001528 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001529 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001530 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1532 "unknown Dell", STAC_9200_DELL_D23),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1534 "unknown Dell", STAC_9200_DELL_D23),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1536 "unknown Dell", STAC_9200_DELL_D21),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1538 "unknown Dell", STAC_9200_DELL_D23),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1540 "unknown Dell", STAC_9200_DELL_D21),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1542 "unknown Dell", STAC_9200_DELL_M25),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1544 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001545 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001546 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1548 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001549 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001550 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001551 /* Gateway machines needs EAPD to be set on resume */
1552 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1553 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1554 STAC_9200_GATEWAY),
1555 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1556 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001557 /* OQO Mobile */
1558 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001559 {} /* terminator */
1560};
1561
Tobin Davis8e21c342007-01-08 11:04:17 +01001562static unsigned int ref925x_pin_configs[8] = {
1563 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001564 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001565};
1566
1567static unsigned int stac925x_MA6_pin_configs[8] = {
1568 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1569 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1570};
1571
Tobin Davis2c11f952007-05-17 09:36:34 +02001572static unsigned int stac925x_PA6_pin_configs[8] = {
1573 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1574 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1575};
1576
Tobin Davis8e21c342007-01-08 11:04:17 +01001577static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001578 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1579 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001580};
1581
1582static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1583 [STAC_REF] = ref925x_pin_configs,
1584 [STAC_M2_2] = stac925xM2_2_pin_configs,
1585 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001586 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001587};
1588
1589static const char *stac925x_models[STAC_925x_MODELS] = {
1590 [STAC_REF] = "ref",
1591 [STAC_M2_2] = "m2-2",
1592 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001593 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001594};
1595
1596static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1597 /* SigmaTel reference board */
1598 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001599 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001600 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1601 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1602 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001603 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001604 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1605 {} /* terminator */
1606};
1607
Matthew Ranostaya7662642008-02-21 07:51:14 +01001608static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001609 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1610 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1611 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001612 0x01452050,
1613};
1614
1615static unsigned int dell_m6_pin_configs[13] = {
1616 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001617 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001618 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1619 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001620};
1621
1622static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001623 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1624 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001625};
1626
1627static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1628 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001629 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001630};
1631
1632static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1633 /* SigmaTel reference board */
1634 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001635 "DFI LanParty", STAC_92HD73XX_REF),
1636 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1637 "unknown Dell", STAC_DELL_M6),
1638 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1639 "unknown Dell", STAC_DELL_M6),
1640 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1641 "unknown Dell", STAC_DELL_M6),
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1643 "unknown Dell", STAC_DELL_M6),
1644 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1645 "unknown Dell", STAC_DELL_M6),
1646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1647 "unknown Dell", STAC_DELL_M6),
1648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1649 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001650 {} /* terminator */
1651};
1652
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001653static unsigned int ref92hd83xxx_pin_configs[14] = {
1654 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1655 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1656 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1657 0x01451160, 0x98560170,
1658};
1659
1660static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1661 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1662};
1663
1664static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1665 [STAC_92HD83XXX_REF] = "ref",
1666};
1667
1668static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1669 /* SigmaTel reference board */
1670 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1671 "DFI LanParty", STAC_92HD71BXX_REF),
1672};
1673
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001674static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001675 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001676 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001677 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001678};
1679
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001680static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001681 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001682 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001683 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001684};
1685
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001686static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001687 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1688 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001689 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001690};
1691
Matthew Ranostaye035b842007-11-06 11:53:55 +01001692static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1693 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001694 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1695 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001696 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001697};
1698
1699static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1700 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001701 [STAC_DELL_M4_1] = "dell-m4-1",
1702 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001703 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001704};
1705
1706static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1707 /* SigmaTel reference board */
1708 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1709 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04001710 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
1711 "unknown HP", STAC_HP_M4),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001712 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1713 "unknown Dell", STAC_DELL_M4_1),
1714 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1715 "unknown Dell", STAC_DELL_M4_1),
1716 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1717 "unknown Dell", STAC_DELL_M4_1),
1718 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1719 "unknown Dell", STAC_DELL_M4_1),
1720 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1721 "unknown Dell", STAC_DELL_M4_1),
1722 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1723 "unknown Dell", STAC_DELL_M4_1),
1724 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1725 "unknown Dell", STAC_DELL_M4_1),
1726 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1727 "unknown Dell", STAC_DELL_M4_2),
1728 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1729 "unknown Dell", STAC_DELL_M4_2),
1730 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1731 "unknown Dell", STAC_DELL_M4_2),
1732 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1733 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001734 {} /* terminator */
1735};
1736
Matt Porter403d1942005-11-29 15:00:51 +01001737static unsigned int ref922x_pin_configs[10] = {
1738 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1739 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001740 0x40000100, 0x40000100,
1741};
1742
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001743/*
1744 STAC 922X pin configs for
1745 102801A7
1746 102801AB
1747 102801A9
1748 102801D1
1749 102801D2
1750*/
1751static unsigned int dell_922x_d81_pin_configs[10] = {
1752 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1753 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1754 0x01813122, 0x400001f2,
1755};
1756
1757/*
1758 STAC 922X pin configs for
1759 102801AC
1760 102801D0
1761*/
1762static unsigned int dell_922x_d82_pin_configs[10] = {
1763 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1764 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1765 0x01813122, 0x400001f1,
1766};
1767
1768/*
1769 STAC 922X pin configs for
1770 102801BF
1771*/
1772static unsigned int dell_922x_m81_pin_configs[10] = {
1773 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1774 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1775 0x40C003f1, 0x405003f0,
1776};
1777
1778/*
1779 STAC 9221 A1 pin configs for
1780 102801D7 (Dell XPS M1210)
1781*/
1782static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001783 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1784 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001785 0x508003f3, 0x405003f4,
1786};
1787
Matt Porter403d1942005-11-29 15:00:51 +01001788static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001789 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001790 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1791 0x02a19120, 0x40000100,
1792};
1793
1794static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001795 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1796 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001797 0x02a19320, 0x40000100,
1798};
1799
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001800static unsigned int intel_mac_v1_pin_configs[10] = {
1801 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1802 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001803 0x400000fc, 0x400000fb,
1804};
1805
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001806static unsigned int intel_mac_v2_pin_configs[10] = {
1807 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1808 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001809 0x400000fc, 0x400000fb,
1810};
1811
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001812static unsigned int intel_mac_v3_pin_configs[10] = {
1813 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1814 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1815 0x400000fc, 0x400000fb,
1816};
1817
1818static unsigned int intel_mac_v4_pin_configs[10] = {
1819 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1820 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1821 0x400000fc, 0x400000fb,
1822};
1823
1824static unsigned int intel_mac_v5_pin_configs[10] = {
1825 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1826 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1827 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001828};
1829
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001830static unsigned int ecs202_pin_configs[10] = {
1831 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1832 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1833 0x9037012e, 0x40e000f2,
1834};
Takashi Iwai76c08822007-06-19 12:17:42 +02001835
Takashi Iwai19039bd2006-06-28 15:52:16 +02001836static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001837 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001838 [STAC_D945GTP3] = d945gtp3_pin_configs,
1839 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001840 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1841 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1842 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1843 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1844 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001845 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001846 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001847 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1848 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1849 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1850 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1851 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1852 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001853 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001854 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1855 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1856 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1857 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001858};
1859
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001860static const char *stac922x_models[STAC_922X_MODELS] = {
1861 [STAC_D945_REF] = "ref",
1862 [STAC_D945GTP5] = "5stack",
1863 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001864 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1865 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1866 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1867 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1868 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001869 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001870 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001871 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001872 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001873 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1874 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001875 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001876 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001877 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001878 [STAC_922X_DELL_D81] = "dell-d81",
1879 [STAC_922X_DELL_D82] = "dell-d82",
1880 [STAC_922X_DELL_M81] = "dell-m81",
1881 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001882};
1883
1884static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1885 /* SigmaTel reference board */
1886 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1887 "DFI LanParty", STAC_D945_REF),
1888 /* Intel 945G based systems */
1889 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1890 "Intel D945G", STAC_D945GTP3),
1891 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1892 "Intel D945G", STAC_D945GTP3),
1893 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1894 "Intel D945G", STAC_D945GTP3),
1895 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1896 "Intel D945G", STAC_D945GTP3),
1897 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1898 "Intel D945G", STAC_D945GTP3),
1899 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1900 "Intel D945G", STAC_D945GTP3),
1901 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1902 "Intel D945G", STAC_D945GTP3),
1903 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1904 "Intel D945G", STAC_D945GTP3),
1905 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1906 "Intel D945G", STAC_D945GTP3),
1907 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1908 "Intel D945G", STAC_D945GTP3),
1909 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1910 "Intel D945G", STAC_D945GTP3),
1911 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1912 "Intel D945G", STAC_D945GTP3),
1913 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1914 "Intel D945G", STAC_D945GTP3),
1915 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1916 "Intel D945G", STAC_D945GTP3),
1917 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1918 "Intel D945G", STAC_D945GTP3),
1919 /* Intel D945G 5-stack systems */
1920 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1921 "Intel D945G", STAC_D945GTP5),
1922 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1923 "Intel D945G", STAC_D945GTP5),
1924 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1925 "Intel D945G", STAC_D945GTP5),
1926 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1927 "Intel D945G", STAC_D945GTP5),
1928 /* Intel 945P based systems */
1929 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1930 "Intel D945P", STAC_D945GTP3),
1931 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1932 "Intel D945P", STAC_D945GTP3),
1933 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1934 "Intel D945P", STAC_D945GTP3),
1935 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1936 "Intel D945P", STAC_D945GTP3),
1937 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1938 "Intel D945P", STAC_D945GTP3),
1939 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1940 "Intel D945P", STAC_D945GTP5),
1941 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001942 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001943 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001944 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001945 /* Dell systems */
1946 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1947 "unknown Dell", STAC_922X_DELL_D81),
1948 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1949 "unknown Dell", STAC_922X_DELL_D81),
1950 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1951 "unknown Dell", STAC_922X_DELL_D81),
1952 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1953 "unknown Dell", STAC_922X_DELL_D82),
1954 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1955 "unknown Dell", STAC_922X_DELL_M81),
1956 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1957 "unknown Dell", STAC_922X_DELL_D82),
1958 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1959 "unknown Dell", STAC_922X_DELL_D81),
1960 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1961 "unknown Dell", STAC_922X_DELL_D81),
1962 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1963 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001964 /* ECS/PC Chips boards */
1965 SND_PCI_QUIRK(0x1019, 0x2144,
1966 "ECS/PC chips", STAC_ECS_202),
1967 SND_PCI_QUIRK(0x1019, 0x2608,
1968 "ECS/PC chips", STAC_ECS_202),
1969 SND_PCI_QUIRK(0x1019, 0x2633,
1970 "ECS/PC chips P17G/1333", STAC_ECS_202),
1971 SND_PCI_QUIRK(0x1019, 0x2811,
1972 "ECS/PC chips", STAC_ECS_202),
1973 SND_PCI_QUIRK(0x1019, 0x2812,
1974 "ECS/PC chips", STAC_ECS_202),
1975 SND_PCI_QUIRK(0x1019, 0x2813,
1976 "ECS/PC chips", STAC_ECS_202),
1977 SND_PCI_QUIRK(0x1019, 0x2814,
1978 "ECS/PC chips", STAC_ECS_202),
1979 SND_PCI_QUIRK(0x1019, 0x2815,
1980 "ECS/PC chips", STAC_ECS_202),
1981 SND_PCI_QUIRK(0x1019, 0x2816,
1982 "ECS/PC chips", STAC_ECS_202),
1983 SND_PCI_QUIRK(0x1019, 0x2817,
1984 "ECS/PC chips", STAC_ECS_202),
1985 SND_PCI_QUIRK(0x1019, 0x2818,
1986 "ECS/PC chips", STAC_ECS_202),
1987 SND_PCI_QUIRK(0x1019, 0x2819,
1988 "ECS/PC chips", STAC_ECS_202),
1989 SND_PCI_QUIRK(0x1019, 0x2820,
1990 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001991 {} /* terminator */
1992};
1993
Matt Porter3cc08dc2006-01-23 15:27:49 +01001994static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001995 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1996 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1997 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1998 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001999};
2000
Tobin Davis93ed1502006-09-01 21:03:12 +02002001static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002002 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
2003 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
2004 0x40000100, 0x40000100, 0x40000100, 0x40000100,
2005 0x40000100, 0x40000100
2006};
2007
Tobin Davis93ed1502006-09-01 21:03:12 +02002008static unsigned int d965_5st_pin_configs[14] = {
2009 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2010 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
2011 0x40000100, 0x40000100, 0x40000100, 0x01442070,
2012 0x40000100, 0x40000100
2013};
2014
Tobin Davis4ff076e2007-08-07 11:48:12 +02002015static unsigned int dell_3st_pin_configs[14] = {
2016 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
2017 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002018 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02002019 0x40c003fc, 0x40000100
2020};
2021
Tobin Davis93ed1502006-09-01 21:03:12 +02002022static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002023 [STAC_D965_REF] = ref927x_pin_configs,
2024 [STAC_D965_3ST] = d965_3st_pin_configs,
2025 [STAC_D965_5ST] = d965_5st_pin_configs,
2026 [STAC_DELL_3ST] = dell_3st_pin_configs,
2027 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002028};
2029
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002030static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002031 [STAC_D965_REF] = "ref",
2032 [STAC_D965_3ST] = "3stack",
2033 [STAC_D965_5ST] = "5stack",
2034 [STAC_DELL_3ST] = "dell-3stack",
2035 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002036};
2037
2038static struct snd_pci_quirk stac927x_cfg_tbl[] = {
2039 /* SigmaTel reference board */
2040 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2041 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002042 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002043 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2044 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002045 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002046 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
2047 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
2048 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
2049 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
2050 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
2051 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
2052 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
2053 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
2054 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
2055 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
2056 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
2057 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
2058 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
2059 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
2060 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
2061 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002062 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002063 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002064 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002065 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2066 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002067 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002068 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
2069 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002070 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02002071 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002072 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2073 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2074 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2075 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002076 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002077 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
2078 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
2079 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
2080 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
2081 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
2082 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
2083 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
2084 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
2085 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002086 {} /* terminator */
2087};
2088
Matt Porterf3302a52006-07-31 12:49:34 +02002089static unsigned int ref9205_pin_configs[12] = {
2090 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002091 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02002092 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02002093};
2094
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002095/*
2096 STAC 9205 pin configs for
2097 102801F1
2098 102801F2
2099 102801FC
2100 102801FD
2101 10280204
2102 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002103 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002104*/
2105static unsigned int dell_9205_m42_pin_configs[12] = {
2106 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
2107 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
2108 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
2109};
2110
2111/*
2112 STAC 9205 pin configs for
2113 102801F9
2114 102801FA
2115 102801FE
2116 102801FF (Dell Precision M4300)
2117 10280206
2118 10280200
2119 10280201
2120*/
2121static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002122 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
2123 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
2124 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
2125};
2126
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002127static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002128 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
2129 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
2130 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
2131};
2132
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002133static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002134 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002135 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
2136 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
2137 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02002138};
2139
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002140static const char *stac9205_models[STAC_9205_MODELS] = {
2141 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002142 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002143 [STAC_9205_DELL_M43] = "dell-m43",
2144 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002145};
2146
2147static struct snd_pci_quirk stac9205_cfg_tbl[] = {
2148 /* SigmaTel reference board */
2149 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2150 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002151 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2152 "unknown Dell", STAC_9205_DELL_M42),
2153 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2154 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002155 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002156 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002157 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2158 "Dell Precision", STAC_9205_DELL_M43),
2159 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2160 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002161 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2162 "unknown Dell", STAC_9205_DELL_M42),
2163 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2164 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002165 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2166 "Dell Precision", STAC_9205_DELL_M43),
2167 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002168 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002169 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2170 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002171 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2172 "Dell Precision", STAC_9205_DELL_M43),
2173 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2174 "Dell Precision", STAC_9205_DELL_M43),
2175 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2176 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002177 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2178 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002179 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2180 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002181 {} /* terminator */
2182};
2183
Richard Fish11b44bb2006-08-23 18:31:34 +02002184static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2185{
2186 int i;
2187 struct sigmatel_spec *spec = codec->spec;
2188
2189 if (! spec->bios_pin_configs) {
2190 spec->bios_pin_configs = kcalloc(spec->num_pins,
2191 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2192 if (! spec->bios_pin_configs)
2193 return -ENOMEM;
2194 }
2195
2196 for (i = 0; i < spec->num_pins; i++) {
2197 hda_nid_t nid = spec->pin_nids[i];
2198 unsigned int pin_cfg;
2199
2200 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2201 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2202 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2203 nid, pin_cfg);
2204 spec->bios_pin_configs[i] = pin_cfg;
2205 }
2206
2207 return 0;
2208}
2209
Matthew Ranostay87d48362007-07-17 11:52:24 +02002210static void stac92xx_set_config_reg(struct hda_codec *codec,
2211 hda_nid_t pin_nid, unsigned int pin_config)
2212{
2213 int i;
2214 snd_hda_codec_write(codec, pin_nid, 0,
2215 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2216 pin_config & 0x000000ff);
2217 snd_hda_codec_write(codec, pin_nid, 0,
2218 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2219 (pin_config & 0x0000ff00) >> 8);
2220 snd_hda_codec_write(codec, pin_nid, 0,
2221 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2222 (pin_config & 0x00ff0000) >> 16);
2223 snd_hda_codec_write(codec, pin_nid, 0,
2224 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2225 pin_config >> 24);
2226 i = snd_hda_codec_read(codec, pin_nid, 0,
2227 AC_VERB_GET_CONFIG_DEFAULT,
2228 0x00);
2229 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2230 pin_nid, i);
2231}
2232
Matt2f2f4252005-04-13 14:45:30 +02002233static void stac92xx_set_config_regs(struct hda_codec *codec)
2234{
2235 int i;
2236 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002237
Matthew Ranostay87d48362007-07-17 11:52:24 +02002238 if (!spec->pin_configs)
2239 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002240
Matthew Ranostay87d48362007-07-17 11:52:24 +02002241 for (i = 0; i < spec->num_pins; i++)
2242 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2243 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002244}
Matt2f2f4252005-04-13 14:45:30 +02002245
Matt2f2f4252005-04-13 14:45:30 +02002246/*
2247 * Analog playback callbacks
2248 */
2249static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2250 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002251 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002252{
2253 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002254 if (spec->stream_delay)
2255 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002256 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2257 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002258}
2259
2260static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2261 struct hda_codec *codec,
2262 unsigned int stream_tag,
2263 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002264 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002265{
2266 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002267 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002268}
2269
2270static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2271 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002272 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002273{
2274 struct sigmatel_spec *spec = codec->spec;
2275 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2276}
2277
2278/*
Mattdabbed62005-06-14 10:19:34 +02002279 * Digital playback callbacks
2280 */
2281static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2282 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002283 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002284{
2285 struct sigmatel_spec *spec = codec->spec;
2286 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2287}
2288
2289static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2290 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002291 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002292{
2293 struct sigmatel_spec *spec = codec->spec;
2294 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2295}
2296
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002297static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2298 struct hda_codec *codec,
2299 unsigned int stream_tag,
2300 unsigned int format,
2301 struct snd_pcm_substream *substream)
2302{
2303 struct sigmatel_spec *spec = codec->spec;
2304 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2305 stream_tag, format, substream);
2306}
2307
Mattdabbed62005-06-14 10:19:34 +02002308
2309/*
Matt2f2f4252005-04-13 14:45:30 +02002310 * Analog capture callbacks
2311 */
2312static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2313 struct hda_codec *codec,
2314 unsigned int stream_tag,
2315 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002316 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002317{
2318 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002319 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002320
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002321 if (spec->powerdown_adcs) {
2322 msleep(40);
2323 snd_hda_codec_write_cache(codec, nid, 0,
2324 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2325 }
2326 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002327 return 0;
2328}
2329
2330static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2331 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002332 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002333{
2334 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002335 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002336
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002337 snd_hda_codec_cleanup_stream(codec, nid);
2338 if (spec->powerdown_adcs)
2339 snd_hda_codec_write_cache(codec, nid, 0,
2340 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002341 return 0;
2342}
2343
Mattdabbed62005-06-14 10:19:34 +02002344static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2345 .substreams = 1,
2346 .channels_min = 2,
2347 .channels_max = 2,
2348 /* NID is set in stac92xx_build_pcms */
2349 .ops = {
2350 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002351 .close = stac92xx_dig_playback_pcm_close,
2352 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002353 },
2354};
2355
2356static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2357 .substreams = 1,
2358 .channels_min = 2,
2359 .channels_max = 2,
2360 /* NID is set in stac92xx_build_pcms */
2361};
2362
Matt2f2f4252005-04-13 14:45:30 +02002363static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2364 .substreams = 1,
2365 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002366 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002367 .nid = 0x02, /* NID to query formats and rates */
2368 .ops = {
2369 .open = stac92xx_playback_pcm_open,
2370 .prepare = stac92xx_playback_pcm_prepare,
2371 .cleanup = stac92xx_playback_pcm_cleanup
2372 },
2373};
2374
Matt Porter3cc08dc2006-01-23 15:27:49 +01002375static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2376 .substreams = 1,
2377 .channels_min = 2,
2378 .channels_max = 2,
2379 .nid = 0x06, /* NID to query formats and rates */
2380 .ops = {
2381 .open = stac92xx_playback_pcm_open,
2382 .prepare = stac92xx_playback_pcm_prepare,
2383 .cleanup = stac92xx_playback_pcm_cleanup
2384 },
2385};
2386
Matt2f2f4252005-04-13 14:45:30 +02002387static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002388 .channels_min = 2,
2389 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002390 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002391 .ops = {
2392 .prepare = stac92xx_capture_pcm_prepare,
2393 .cleanup = stac92xx_capture_pcm_cleanup
2394 },
2395};
2396
2397static int stac92xx_build_pcms(struct hda_codec *codec)
2398{
2399 struct sigmatel_spec *spec = codec->spec;
2400 struct hda_pcm *info = spec->pcm_rec;
2401
2402 codec->num_pcms = 1;
2403 codec->pcm_info = info;
2404
Mattc7d4b2f2005-06-27 14:59:41 +02002405 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002406 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002407 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002408 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002409 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002410
2411 if (spec->alt_switch) {
2412 codec->num_pcms++;
2413 info++;
2414 info->name = "STAC92xx Analog Alt";
2415 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2416 }
Matt2f2f4252005-04-13 14:45:30 +02002417
Mattdabbed62005-06-14 10:19:34 +02002418 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2419 codec->num_pcms++;
2420 info++;
2421 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002422 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002423 if (spec->multiout.dig_out_nid) {
2424 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2425 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2426 }
2427 if (spec->dig_in_nid) {
2428 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2429 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2430 }
2431 }
2432
Matt2f2f4252005-04-13 14:45:30 +02002433 return 0;
2434}
2435
Takashi Iwaic960a032006-03-23 17:06:28 +01002436static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2437{
2438 unsigned int pincap = snd_hda_param_read(codec, nid,
2439 AC_PAR_PIN_CAP);
2440 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2441 if (pincap & AC_PINCAP_VREF_100)
2442 return AC_PINCTL_VREF_100;
2443 if (pincap & AC_PINCAP_VREF_80)
2444 return AC_PINCTL_VREF_80;
2445 if (pincap & AC_PINCAP_VREF_50)
2446 return AC_PINCTL_VREF_50;
2447 if (pincap & AC_PINCAP_VREF_GRD)
2448 return AC_PINCTL_VREF_GRD;
2449 return 0;
2450}
2451
Matt Porter403d1942005-11-29 15:00:51 +01002452static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2453
2454{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002455 snd_hda_codec_write_cache(codec, nid, 0,
2456 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002457}
2458
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002459#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2460
2461static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2462 struct snd_ctl_elem_value *ucontrol)
2463{
2464 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2465 struct sigmatel_spec *spec = codec->spec;
2466
2467 ucontrol->value.integer.value[0] = spec->hp_switch;
2468 return 0;
2469}
2470
2471static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2472 struct snd_ctl_elem_value *ucontrol)
2473{
2474 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2475 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002476 struct auto_pin_cfg *cfg = &spec->autocfg;
2477 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002478
2479 spec->hp_switch = ucontrol->value.integer.value[0];
2480
2481 /* check to be sure that the ports are upto date with
2482 * switch changes
2483 */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002484 codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002485
2486 return 1;
2487}
2488
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002489#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002490
2491static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2492{
2493 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2494 struct sigmatel_spec *spec = codec->spec;
2495 int io_idx = kcontrol-> private_value & 0xff;
2496
2497 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2498 return 0;
2499}
2500
2501static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2502{
2503 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2504 struct sigmatel_spec *spec = codec->spec;
2505 hda_nid_t nid = kcontrol->private_value >> 8;
2506 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002507 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002508
2509 spec->io_switch[io_idx] = val;
2510
2511 if (val)
2512 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002513 else {
2514 unsigned int pinctl = AC_PINCTL_IN_EN;
2515 if (io_idx) /* set VREF for mic */
2516 pinctl |= stac92xx_get_vref(codec, nid);
2517 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2518 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002519
2520 /* check the auto-mute again: we need to mute/unmute the speaker
2521 * appropriately according to the pin direction
2522 */
2523 if (spec->hp_detect)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002524 codec->patch_ops.unsol_event(codec,
2525 (STAC_HP_EVENT | nid) << 26);
Jiang Zhe40c1d302007-11-12 13:05:16 +01002526
Matt Porter403d1942005-11-29 15:00:51 +01002527 return 1;
2528}
2529
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002530#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2531
2532static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2533 struct snd_ctl_elem_value *ucontrol)
2534{
2535 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2536 struct sigmatel_spec *spec = codec->spec;
2537
2538 ucontrol->value.integer.value[0] = spec->clfe_swap;
2539 return 0;
2540}
2541
2542static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2543 struct snd_ctl_elem_value *ucontrol)
2544{
2545 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2546 struct sigmatel_spec *spec = codec->spec;
2547 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002548 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002549
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002550 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002551 return 0;
2552
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002553 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002554
2555 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2556 spec->clfe_swap ? 0x4 : 0x0);
2557
2558 return 1;
2559}
2560
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002561#define STAC_CODEC_HP_SWITCH(xname) \
2562 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2563 .name = xname, \
2564 .index = 0, \
2565 .info = stac92xx_hp_switch_info, \
2566 .get = stac92xx_hp_switch_get, \
2567 .put = stac92xx_hp_switch_put, \
2568 }
2569
Matt Porter403d1942005-11-29 15:00:51 +01002570#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2571 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2572 .name = xname, \
2573 .index = 0, \
2574 .info = stac92xx_io_switch_info, \
2575 .get = stac92xx_io_switch_get, \
2576 .put = stac92xx_io_switch_put, \
2577 .private_value = xpval, \
2578 }
2579
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002580#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2581 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2582 .name = xname, \
2583 .index = 0, \
2584 .info = stac92xx_clfe_switch_info, \
2585 .get = stac92xx_clfe_switch_get, \
2586 .put = stac92xx_clfe_switch_put, \
2587 .private_value = xpval, \
2588 }
Matt Porter403d1942005-11-29 15:00:51 +01002589
Mattc7d4b2f2005-06-27 14:59:41 +02002590enum {
2591 STAC_CTL_WIDGET_VOL,
2592 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002593 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002594 STAC_CTL_WIDGET_AMP_MUX,
2595 STAC_CTL_WIDGET_AMP_VOL,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002596 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002597 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002598 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002599};
2600
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002601static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002602 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2603 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002604 STAC_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002605 STAC_AMP_MUX,
2606 STAC_AMP_VOL(NULL, 0, 0, 0, 0),
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002607 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002608 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002609 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002610};
2611
2612/* add dynamic controls */
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002613static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
2614 int idx, const char *name, unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002615{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002616 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002617
Takashi Iwai603c4012008-07-30 15:01:44 +02002618 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2619 knew = snd_array_new(&spec->kctls);
2620 if (!knew)
2621 return -ENOMEM;
Mattc7d4b2f2005-06-27 14:59:41 +02002622 *knew = stac92xx_control_templates[type];
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002623 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002624 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002625 if (! knew->name)
2626 return -ENOMEM;
2627 knew->private_value = val;
Mattc7d4b2f2005-06-27 14:59:41 +02002628 return 0;
2629}
2630
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002631
2632/* add dynamic controls */
2633static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2634 const char *name, unsigned long val)
2635{
2636 return stac92xx_add_control_idx(spec, type, 0, name, val);
2637}
2638
Matt Porter403d1942005-11-29 15:00:51 +01002639/* flag inputs as additional dynamic lineouts */
2640static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2641{
2642 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002643 unsigned int wcaps, wtype;
2644 int i, num_dacs = 0;
2645
2646 /* use the wcaps cache to count all DACs available for line-outs */
2647 for (i = 0; i < codec->num_nodes; i++) {
2648 wcaps = codec->wcaps[i];
2649 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002650
Steve Longerbeam7b043892007-05-03 20:50:03 +02002651 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2652 num_dacs++;
2653 }
Matt Porter403d1942005-11-29 15:00:51 +01002654
Steve Longerbeam7b043892007-05-03 20:50:03 +02002655 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2656
Matt Porter403d1942005-11-29 15:00:51 +01002657 switch (cfg->line_outs) {
2658 case 3:
2659 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002660 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002661 cfg->line_out_pins[cfg->line_outs] =
2662 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002663 spec->line_switch = 1;
2664 cfg->line_outs++;
2665 }
2666 break;
2667 case 2:
2668 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002669 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002670 cfg->line_out_pins[cfg->line_outs] =
2671 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002672 spec->line_switch = 1;
2673 cfg->line_outs++;
2674 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002675 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002676 cfg->line_out_pins[cfg->line_outs] =
2677 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002678 spec->mic_switch = 1;
2679 cfg->line_outs++;
2680 }
2681 break;
2682 case 1:
2683 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002684 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002685 cfg->line_out_pins[cfg->line_outs] =
2686 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002687 spec->line_switch = 1;
2688 cfg->line_outs++;
2689 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002690 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002691 cfg->line_out_pins[cfg->line_outs] =
2692 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002693 spec->mic_switch = 1;
2694 cfg->line_outs++;
2695 }
2696 break;
2697 }
2698
2699 return 0;
2700}
2701
Steve Longerbeam7b043892007-05-03 20:50:03 +02002702
2703static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2704{
2705 int i;
2706
2707 for (i = 0; i < spec->multiout.num_dacs; i++) {
2708 if (spec->multiout.dac_nids[i] == nid)
2709 return 1;
2710 }
2711
2712 return 0;
2713}
2714
Matt Porter3cc08dc2006-01-23 15:27:49 +01002715/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002716 * Fill in the dac_nids table from the parsed pin configuration
2717 * This function only works when every pin in line_out_pins[]
2718 * contains atleast one DAC in its connection list. Some 92xx
2719 * codecs are not connected directly to a DAC, such as the 9200
2720 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002721 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002722static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002723 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002724{
2725 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002726 int i, j, conn_len = 0;
2727 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2728 unsigned int wcaps, wtype;
2729
Mattc7d4b2f2005-06-27 14:59:41 +02002730 for (i = 0; i < cfg->line_outs; i++) {
2731 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002732 conn_len = snd_hda_get_connections(codec, nid, conn,
2733 HDA_MAX_CONNECTIONS);
2734 for (j = 0; j < conn_len; j++) {
2735 wcaps = snd_hda_param_read(codec, conn[j],
2736 AC_PAR_AUDIO_WIDGET_CAP);
2737 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002738 if (wtype != AC_WID_AUD_OUT ||
2739 (wcaps & AC_WCAP_DIGITAL))
2740 continue;
2741 /* conn[j] is a DAC routed to this line-out */
2742 if (!is_in_dac_nids(spec, conn[j]))
2743 break;
2744 }
2745
2746 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002747 if (spec->multiout.num_dacs > 0) {
2748 /* we have already working output pins,
2749 * so let's drop the broken ones again
2750 */
2751 cfg->line_outs = spec->multiout.num_dacs;
2752 break;
2753 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002754 /* error out, no available DAC found */
2755 snd_printk(KERN_ERR
2756 "%s: No available DAC for pin 0x%x\n",
2757 __func__, nid);
2758 return -ENODEV;
2759 }
2760
2761 spec->multiout.dac_nids[i] = conn[j];
2762 spec->multiout.num_dacs++;
2763 if (conn_len > 1) {
2764 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002765 snd_hda_codec_write_cache(codec, nid, 0,
2766 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002767
2768 }
Mattc7d4b2f2005-06-27 14:59:41 +02002769 }
2770
Steve Longerbeam7b043892007-05-03 20:50:03 +02002771 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2772 spec->multiout.num_dacs,
2773 spec->multiout.dac_nids[0],
2774 spec->multiout.dac_nids[1],
2775 spec->multiout.dac_nids[2],
2776 spec->multiout.dac_nids[3],
2777 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002778 return 0;
2779}
2780
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002781/* create volume control/switch for the given prefx type */
2782static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2783{
2784 char name[32];
2785 int err;
2786
2787 sprintf(name, "%s Playback Volume", pfx);
2788 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2789 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2790 if (err < 0)
2791 return err;
2792 sprintf(name, "%s Playback Switch", pfx);
2793 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2794 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2795 if (err < 0)
2796 return err;
2797 return 0;
2798}
2799
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002800static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2801{
2802 if (!spec->multiout.hp_nid)
2803 spec->multiout.hp_nid = nid;
2804 else if (spec->multiout.num_dacs > 4) {
2805 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2806 return 1;
2807 } else {
2808 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2809 spec->multiout.num_dacs++;
2810 }
2811 return 0;
2812}
2813
2814static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2815{
2816 if (is_in_dac_nids(spec, nid))
2817 return 1;
2818 if (spec->multiout.hp_nid == nid)
2819 return 1;
2820 return 0;
2821}
2822
Mattc7d4b2f2005-06-27 14:59:41 +02002823/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002824static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002825 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002826{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002827 static const char *chname[4] = {
2828 "Front", "Surround", NULL /*CLFE*/, "Side"
2829 };
Matthew Ranostayd21995e2008-10-13 13:22:45 -04002830 hda_nid_t nid = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002831 int i, err;
2832
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002833 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002834 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002835
2836
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002837 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002838 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002839 continue;
2840
2841 nid = spec->multiout.dac_nids[i];
2842
2843 if (i == 2) {
2844 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002845 err = create_controls(spec, "Center", nid, 1);
2846 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002847 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002848 err = create_controls(spec, "LFE", nid, 2);
2849 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002850 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002851
2852 wid_caps = get_wcaps(codec, nid);
2853
2854 if (wid_caps & AC_WCAP_LR_SWAP) {
2855 err = stac92xx_add_control(spec,
2856 STAC_CTL_WIDGET_CLFE_SWITCH,
2857 "Swap Center/LFE Playback Switch", nid);
2858
2859 if (err < 0)
2860 return err;
2861 }
2862
Mattc7d4b2f2005-06-27 14:59:41 +02002863 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002864 err = create_controls(spec, chname[i], nid, 3);
2865 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002866 return err;
2867 }
2868 }
2869
Matthew Ranostayfedb7562008-09-23 21:46:30 -04002870 if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
2871 cfg->hp_outs && !spec->multiout.hp_nid)
2872 spec->multiout.hp_nid = nid;
2873
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002874 if (cfg->hp_outs > 1) {
2875 err = stac92xx_add_control(spec,
2876 STAC_CTL_WIDGET_HP_SWITCH,
2877 "Headphone as Line Out Switch", 0);
2878 if (err < 0)
2879 return err;
2880 }
2881
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002882 if (spec->line_switch) {
2883 nid = cfg->input_pins[AUTO_PIN_LINE];
2884 pincap = snd_hda_param_read(codec, nid,
2885 AC_PAR_PIN_CAP);
2886 if (pincap & AC_PINCAP_OUT) {
2887 err = stac92xx_add_control(spec,
2888 STAC_CTL_WIDGET_IO_SWITCH,
2889 "Line In as Output Switch", nid << 8);
2890 if (err < 0)
2891 return err;
2892 }
2893 }
Matt Porter403d1942005-11-29 15:00:51 +01002894
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002895 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002896 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002897 unsigned int mic_pin = AUTO_PIN_MIC;
2898again:
2899 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002900 def_conf = snd_hda_codec_read(codec, nid, 0,
2901 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002902 /* some laptops have an internal analog microphone
2903 * which can't be used as a output */
2904 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2905 pincap = snd_hda_param_read(codec, nid,
2906 AC_PAR_PIN_CAP);
2907 if (pincap & AC_PINCAP_OUT) {
2908 err = stac92xx_add_control(spec,
2909 STAC_CTL_WIDGET_IO_SWITCH,
2910 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002911 nid = snd_hda_codec_read(codec, nid, 0,
2912 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2913 if (!check_in_dac_nids(spec, nid))
2914 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002915 if (err < 0)
2916 return err;
2917 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002918 } else if (mic_pin == AUTO_PIN_MIC) {
2919 mic_pin = AUTO_PIN_FRONT_MIC;
2920 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002921 }
2922 }
Matt Porter403d1942005-11-29 15:00:51 +01002923
Mattc7d4b2f2005-06-27 14:59:41 +02002924 return 0;
2925}
2926
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002927/* add playback controls for Speaker and HP outputs */
2928static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2929 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002930{
2931 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002932 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002933 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002934
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002935 old_num_dacs = spec->multiout.num_dacs;
2936 for (i = 0; i < cfg->hp_outs; i++) {
2937 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2938 if (wid_caps & AC_WCAP_UNSOL_CAP)
2939 spec->hp_detect = 1;
2940 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2941 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2942 if (check_in_dac_nids(spec, nid))
2943 nid = 0;
2944 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002945 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002946 add_spec_dacs(spec, nid);
2947 }
2948 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002949 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002950 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2951 if (check_in_dac_nids(spec, nid))
2952 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002953 if (! nid)
2954 continue;
2955 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002956 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002957 for (i = 0; i < cfg->line_outs; i++) {
2958 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2959 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2960 if (check_in_dac_nids(spec, nid))
2961 nid = 0;
2962 if (! nid)
2963 continue;
2964 add_spec_dacs(spec, nid);
2965 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002966 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2967 static const char *pfxs[] = {
2968 "Speaker", "External Speaker", "Speaker2",
2969 };
2970 err = create_controls(spec, pfxs[i - old_num_dacs],
2971 spec->multiout.dac_nids[i], 3);
2972 if (err < 0)
2973 return err;
2974 }
2975 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002976 err = create_controls(spec, "Headphone",
2977 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002978 if (err < 0)
2979 return err;
2980 }
Mattc7d4b2f2005-06-27 14:59:41 +02002981
2982 return 0;
2983}
2984
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002985/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002986static const char *stac92xx_mono_labels[4] = {
2987 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002988};
2989
2990/* create mono mux for mono out on capable codecs */
2991static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2992{
2993 struct sigmatel_spec *spec = codec->spec;
2994 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2995 int i, num_cons;
2996 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2997
2998 num_cons = snd_hda_get_connections(codec,
2999 spec->mono_nid,
3000 con_lst,
3001 HDA_MAX_NUM_INPUTS);
3002 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
3003 return -EINVAL;
3004
3005 for (i = 0; i < num_cons; i++) {
3006 mono_mux->items[mono_mux->num_items].label =
3007 stac92xx_mono_labels[i];
3008 mono_mux->items[mono_mux->num_items].index = i;
3009 mono_mux->num_items++;
3010 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003011
3012 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
3013 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003014}
3015
Matthew Ranostay89385032008-09-11 09:49:39 -04003016/* labels for amp mux outputs */
3017static const char *stac92xx_amp_labels[3] = {
Matthew Ranostay4b33c762008-10-10 09:07:23 -04003018 "Front Microphone", "Microphone", "Line In",
Matthew Ranostay89385032008-09-11 09:49:39 -04003019};
3020
3021/* create amp out controls mux on capable codecs */
3022static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
3023{
3024 struct sigmatel_spec *spec = codec->spec;
3025 struct hda_input_mux *amp_mux = &spec->private_amp_mux;
3026 int i, err;
3027
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003028 for (i = 0; i < spec->num_amps; i++) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003029 amp_mux->items[amp_mux->num_items].label =
3030 stac92xx_amp_labels[i];
3031 amp_mux->items[amp_mux->num_items].index = i;
3032 amp_mux->num_items++;
3033 }
3034
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003035 if (spec->num_amps > 1) {
3036 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
3037 "Amp Selector Capture Switch", 0);
3038 if (err < 0)
3039 return err;
3040 }
Matthew Ranostay89385032008-09-11 09:49:39 -04003041 return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
3042 "Amp Capture Volume",
3043 HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
3044}
3045
3046
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003047/* create PC beep volume controls */
3048static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3049 hda_nid_t nid)
3050{
3051 struct sigmatel_spec *spec = codec->spec;
3052 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3053 int err;
3054
3055 /* check for mute support for the the amp */
3056 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3057 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3058 "PC Beep Playback Switch",
3059 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3060 if (err < 0)
3061 return err;
3062 }
3063
3064 /* check to see if there is volume support for the amp */
3065 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3066 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
3067 "PC Beep Playback Volume",
3068 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3069 if (err < 0)
3070 return err;
3071 }
3072 return 0;
3073}
3074
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003075static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3076{
3077 struct sigmatel_spec *spec = codec->spec;
3078 int wcaps, nid, i, err = 0;
3079
3080 for (i = 0; i < spec->num_muxes; i++) {
3081 nid = spec->mux_nids[i];
3082 wcaps = get_wcaps(codec, nid);
3083
3084 if (wcaps & AC_WCAP_OUT_AMP) {
3085 err = stac92xx_add_control_idx(spec,
3086 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
3087 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3088 if (err < 0)
3089 return err;
3090 }
3091 }
3092 return 0;
3093};
3094
Matthew Ranostayd9737752008-09-07 12:03:41 +02003095static const char *stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04003096 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02003097};
3098
3099static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
3100{
3101 struct sigmatel_spec *spec = codec->spec;
3102 struct hda_input_mux *spdif_mux = &spec->private_smux;
Matthew Ranostay65973632008-09-16 10:39:37 -04003103 const char **labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003104 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04003105 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003106
3107 num_cons = snd_hda_get_connections(codec,
3108 spec->smux_nids[0],
3109 con_lst,
3110 HDA_MAX_NUM_INPUTS);
Matthew Ranostay65973632008-09-16 10:39:37 -04003111 if (!num_cons)
Matthew Ranostayd9737752008-09-07 12:03:41 +02003112 return -EINVAL;
3113
Matthew Ranostay65973632008-09-16 10:39:37 -04003114 if (!labels)
3115 labels = stac92xx_spdif_labels;
3116
Matthew Ranostayd9737752008-09-07 12:03:41 +02003117 for (i = 0; i < num_cons; i++) {
Matthew Ranostay65973632008-09-16 10:39:37 -04003118 spdif_mux->items[spdif_mux->num_items].label = labels[i];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003119 spdif_mux->items[spdif_mux->num_items].index = i;
3120 spdif_mux->num_items++;
3121 }
3122
3123 return 0;
3124}
3125
Matt Porter8b657272006-10-26 17:12:59 +02003126/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01003127static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02003128 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
3129 "Digital Mic 3", "Digital Mic 4"
3130};
3131
3132/* create playback/capture controls for input pins on dmic capable codecs */
3133static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3134 const struct auto_pin_cfg *cfg)
3135{
3136 struct sigmatel_spec *spec = codec->spec;
3137 struct hda_input_mux *dimux = &spec->private_dimux;
3138 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003139 int err, i, j;
3140 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02003141
3142 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
3143 dimux->items[dimux->num_items].index = 0;
3144 dimux->num_items++;
3145
3146 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003147 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02003148 int index;
3149 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003150 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02003151 unsigned int def_conf;
3152
3153 def_conf = snd_hda_codec_read(codec,
3154 spec->dmic_nids[i],
3155 0,
3156 AC_VERB_GET_CONFIG_DEFAULT,
3157 0);
3158 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
3159 continue;
3160
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003161 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02003162 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003163 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02003164 con_lst,
3165 HDA_MAX_NUM_INPUTS);
3166 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003167 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02003168 index = j;
3169 goto found;
3170 }
3171 continue;
3172found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003173 wcaps = get_wcaps(codec, nid) &
3174 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003175
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003176 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003177 sprintf(name, "%s Capture Volume",
3178 stac92xx_dmic_labels[dimux->num_items]);
3179
3180 err = stac92xx_add_control(spec,
3181 STAC_CTL_WIDGET_VOL,
3182 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003183 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3184 (wcaps & AC_WCAP_OUT_AMP) ?
3185 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003186 if (err < 0)
3187 return err;
3188 }
3189
Matt Porter8b657272006-10-26 17:12:59 +02003190 dimux->items[dimux->num_items].label =
3191 stac92xx_dmic_labels[dimux->num_items];
3192 dimux->items[dimux->num_items].index = index;
3193 dimux->num_items++;
3194 }
3195
3196 return 0;
3197}
3198
Mattc7d4b2f2005-06-27 14:59:41 +02003199/* create playback/capture controls for input pins */
3200static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3201{
3202 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003203 struct hda_input_mux *imux = &spec->private_imux;
3204 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3205 int i, j, k;
3206
3207 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003208 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003209
Takashi Iwai314634b2006-09-21 11:56:18 +02003210 if (!cfg->input_pins[i])
3211 continue;
3212 index = -1;
3213 for (j = 0; j < spec->num_muxes; j++) {
3214 int num_cons;
3215 num_cons = snd_hda_get_connections(codec,
3216 spec->mux_nids[j],
3217 con_lst,
3218 HDA_MAX_NUM_INPUTS);
3219 for (k = 0; k < num_cons; k++)
3220 if (con_lst[k] == cfg->input_pins[i]) {
3221 index = k;
3222 goto found;
3223 }
Mattc7d4b2f2005-06-27 14:59:41 +02003224 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003225 continue;
3226 found:
3227 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3228 imux->items[imux->num_items].index = index;
3229 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003230 }
3231
Steve Longerbeam7b043892007-05-03 20:50:03 +02003232 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003233 /*
3234 * Set the current input for the muxes.
3235 * The STAC9221 has two input muxes with identical source
3236 * NID lists. Hopefully this won't get confused.
3237 */
3238 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003239 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3240 AC_VERB_SET_CONNECT_SEL,
3241 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003242 }
3243 }
3244
Mattc7d4b2f2005-06-27 14:59:41 +02003245 return 0;
3246}
3247
Mattc7d4b2f2005-06-27 14:59:41 +02003248static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3249{
3250 struct sigmatel_spec *spec = codec->spec;
3251 int i;
3252
3253 for (i = 0; i < spec->autocfg.line_outs; i++) {
3254 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3255 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3256 }
3257}
3258
3259static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3260{
3261 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003262 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003263
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003264 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3265 hda_nid_t pin;
3266 pin = spec->autocfg.hp_pins[i];
3267 if (pin) /* connect to front */
3268 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3269 }
3270 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3271 hda_nid_t pin;
3272 pin = spec->autocfg.speaker_pins[i];
3273 if (pin) /* connect to front */
3274 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3275 }
Mattc7d4b2f2005-06-27 14:59:41 +02003276}
3277
Matt Porter3cc08dc2006-01-23 15:27:49 +01003278static 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 +02003279{
3280 struct sigmatel_spec *spec = codec->spec;
3281 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003282 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003283
Matt Porter8b657272006-10-26 17:12:59 +02003284 if ((err = snd_hda_parse_pin_def_config(codec,
3285 &spec->autocfg,
3286 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003287 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003288 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003289 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003290
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003291 /* If we have no real line-out pin and multiple hp-outs, HPs should
3292 * be set up as multi-channel outputs.
3293 */
3294 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3295 spec->autocfg.hp_outs > 1) {
3296 /* Copy hp_outs to line_outs, backup line_outs in
3297 * speaker_outs so that the following routines can handle
3298 * HP pins as primary outputs.
3299 */
3300 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3301 sizeof(spec->autocfg.line_out_pins));
3302 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3303 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3304 sizeof(spec->autocfg.hp_pins));
3305 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3306 hp_speaker_swap = 1;
3307 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003308 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003309 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3310 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003311 u32 caps = query_amp_caps(codec,
3312 spec->autocfg.mono_out_pin, dir);
3313 hda_nid_t conn_list[1];
3314
3315 /* get the mixer node and then the mono mux if it exists */
3316 if (snd_hda_get_connections(codec,
3317 spec->autocfg.mono_out_pin, conn_list, 1) &&
3318 snd_hda_get_connections(codec, conn_list[0],
3319 conn_list, 1)) {
3320
3321 int wcaps = get_wcaps(codec, conn_list[0]);
3322 int wid_type = (wcaps & AC_WCAP_TYPE)
3323 >> AC_WCAP_TYPE_SHIFT;
3324 /* LR swap check, some stac925x have a mux that
3325 * changes the DACs output path instead of the
3326 * mono-mux path.
3327 */
3328 if (wid_type == AC_WID_AUD_SEL &&
3329 !(wcaps & AC_WCAP_LR_SWAP))
3330 spec->mono_nid = conn_list[0];
3331 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003332 if (dir) {
3333 hda_nid_t nid = spec->autocfg.mono_out_pin;
3334
3335 /* most mono outs have a least a mute/unmute switch */
3336 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3337 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3338 "Mono Playback Switch",
3339 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003340 if (err < 0)
3341 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003342 /* check for volume support for the amp */
3343 if ((caps & AC_AMPCAP_NUM_STEPS)
3344 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3345 err = stac92xx_add_control(spec,
3346 STAC_CTL_WIDGET_VOL,
3347 "Mono Playback Volume",
3348 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3349 if (err < 0)
3350 return err;
3351 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003352 }
3353
3354 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3355 AC_PINCTL_OUT_EN);
3356 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003357
Matt Porter403d1942005-11-29 15:00:51 +01003358 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3359 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003360 if (spec->multiout.num_dacs == 0)
3361 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3362 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003363
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003364 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3365
3366 if (err < 0)
3367 return err;
3368
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003369 /* setup analog beep controls */
3370 if (spec->anabeep_nid > 0) {
3371 err = stac92xx_auto_create_beep_ctls(codec,
3372 spec->anabeep_nid);
3373 if (err < 0)
3374 return err;
3375 }
3376
3377 /* setup digital beep controls and input device */
3378#ifdef CONFIG_SND_HDA_INPUT_BEEP
3379 if (spec->digbeep_nid > 0) {
3380 hda_nid_t nid = spec->digbeep_nid;
3381
3382 err = stac92xx_auto_create_beep_ctls(codec, nid);
3383 if (err < 0)
3384 return err;
3385 err = snd_hda_attach_beep_device(codec, nid);
3386 if (err < 0)
3387 return err;
3388 }
3389#endif
3390
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003391 if (hp_speaker_swap == 1) {
3392 /* Restore the hp_outs and line_outs */
3393 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3394 sizeof(spec->autocfg.line_out_pins));
3395 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3396 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3397 sizeof(spec->autocfg.speaker_pins));
3398 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3399 memset(spec->autocfg.speaker_pins, 0,
3400 sizeof(spec->autocfg.speaker_pins));
3401 spec->autocfg.speaker_outs = 0;
3402 }
3403
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003404 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3405
3406 if (err < 0)
3407 return err;
3408
3409 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3410
3411 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003412 return err;
3413
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003414 if (spec->mono_nid > 0) {
3415 err = stac92xx_auto_create_mono_output_ctls(codec);
3416 if (err < 0)
3417 return err;
3418 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003419 if (spec->num_amps > 0) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003420 err = stac92xx_auto_create_amp_output_ctls(codec);
3421 if (err < 0)
3422 return err;
3423 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003424 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02003425 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3426 &spec->autocfg)) < 0)
3427 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003428 if (spec->num_muxes > 0) {
3429 err = stac92xx_auto_create_mux_input_ctls(codec);
3430 if (err < 0)
3431 return err;
3432 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003433 if (spec->num_smuxes > 0) {
3434 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3435 if (err < 0)
3436 return err;
3437 }
Matt Porter8b657272006-10-26 17:12:59 +02003438
Mattc7d4b2f2005-06-27 14:59:41 +02003439 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003440 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003441 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003442
Takashi Iwai82bc9552006-03-21 11:24:42 +01003443 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003444 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003445 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003446 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003447
Takashi Iwai603c4012008-07-30 15:01:44 +02003448 if (spec->kctls.list)
3449 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003450
3451 spec->input_mux = &spec->private_imux;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003452 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003453 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003454 spec->mono_mux = &spec->private_mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -04003455 spec->amp_mux = &spec->private_amp_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003456 return 1;
3457}
3458
Takashi Iwai82bc9552006-03-21 11:24:42 +01003459/* add playback controls for HP output */
3460static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3461 struct auto_pin_cfg *cfg)
3462{
3463 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003464 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003465 unsigned int wid_caps;
3466
3467 if (! pin)
3468 return 0;
3469
3470 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003471 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003472 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003473
3474 return 0;
3475}
3476
Richard Fish160ea0d2006-09-06 13:58:25 +02003477/* add playback controls for LFE output */
3478static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3479 struct auto_pin_cfg *cfg)
3480{
3481 struct sigmatel_spec *spec = codec->spec;
3482 int err;
3483 hda_nid_t lfe_pin = 0x0;
3484 int i;
3485
3486 /*
3487 * search speaker outs and line outs for a mono speaker pin
3488 * with an amp. If one is found, add LFE controls
3489 * for it.
3490 */
3491 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3492 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003493 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003494 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3495 if (wcaps == AC_WCAP_OUT_AMP)
3496 /* found a mono speaker with an amp, must be lfe */
3497 lfe_pin = pin;
3498 }
3499
3500 /* if speaker_outs is 0, then speakers may be in line_outs */
3501 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3502 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3503 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003504 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003505 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003506 AC_VERB_GET_CONFIG_DEFAULT,
3507 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003508 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003509 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003510 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3511 if (wcaps == AC_WCAP_OUT_AMP)
3512 /* found a mono speaker with an amp,
3513 must be lfe */
3514 lfe_pin = pin;
3515 }
3516 }
3517 }
3518
3519 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003520 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003521 if (err < 0)
3522 return err;
3523 }
3524
3525 return 0;
3526}
3527
Mattc7d4b2f2005-06-27 14:59:41 +02003528static int stac9200_parse_auto_config(struct hda_codec *codec)
3529{
3530 struct sigmatel_spec *spec = codec->spec;
3531 int err;
3532
Kailang Yangdf694da2005-12-05 19:42:22 +01003533 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003534 return err;
3535
3536 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3537 return err;
3538
Takashi Iwai82bc9552006-03-21 11:24:42 +01003539 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3540 return err;
3541
Richard Fish160ea0d2006-09-06 13:58:25 +02003542 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3543 return err;
3544
Takashi Iwai82bc9552006-03-21 11:24:42 +01003545 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003546 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003547 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003548 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003549
Takashi Iwai603c4012008-07-30 15:01:44 +02003550 if (spec->kctls.list)
3551 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003552
3553 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003554 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003555
3556 return 1;
3557}
3558
Sam Revitch62fe78e2006-05-10 15:09:17 +02003559/*
3560 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3561 * funky external mute control using GPIO pins.
3562 */
3563
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003564static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003565 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003566{
3567 unsigned int gpiostate, gpiomask, gpiodir;
3568
3569 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3570 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003571 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003572
3573 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3574 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003575 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003576
3577 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3578 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003579 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003580
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003581 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003582 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3583
3584 snd_hda_codec_write(codec, codec->afg, 0,
3585 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003586 snd_hda_codec_read(codec, codec->afg, 0,
3587 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003588
3589 msleep(1);
3590
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003591 snd_hda_codec_read(codec, codec->afg, 0,
3592 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003593}
3594
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003595static int stac92xx_add_jack(struct hda_codec *codec,
3596 hda_nid_t nid, int type)
3597{
3598 struct sigmatel_spec *spec = codec->spec;
3599 struct sigmatel_jack *jack;
3600 int def_conf = snd_hda_codec_read(codec, nid,
3601 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
3602 int connectivity = get_defcfg_connect(def_conf);
3603 char name[32];
3604
3605 if (connectivity && connectivity != AC_JACK_PORT_FIXED)
3606 return 0;
3607
3608 snd_array_init(&spec->jacks, sizeof(*jack), 32);
3609 jack = snd_array_new(&spec->jacks);
3610 if (!jack)
3611 return -ENOMEM;
3612 jack->nid = nid;
3613 jack->type = type;
3614
3615 sprintf(name, "%s at %s %s Jack",
3616 snd_hda_get_jack_type(def_conf),
3617 snd_hda_get_jack_connectivity(def_conf),
3618 snd_hda_get_jack_location(def_conf));
3619
3620 return snd_jack_new(codec->bus->card, name, type, &jack->jack);
3621}
3622
3623static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
3624 int data)
3625{
3626 struct sigmatel_event *event;
3627
3628 snd_array_init(&spec->events, sizeof(*event), 32);
3629 event = snd_array_new(&spec->events);
3630 if (!event)
3631 return -ENOMEM;
3632 event->nid = nid;
3633 event->data = data;
3634
3635 return 0;
3636}
3637
3638static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid)
3639{
3640 struct sigmatel_spec *spec = codec->spec;
3641 struct sigmatel_event *events = spec->events.list;
3642 if (events) {
3643 int i;
3644 for (i = 0; i < spec->events.used; i++)
3645 if (events[i].nid == nid)
3646 return events[i].data;
3647 }
3648 return 0;
3649}
3650
Takashi Iwai314634b2006-09-21 11:56:18 +02003651static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3652 unsigned int event)
3653{
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003654 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003655 snd_hda_codec_write_cache(codec, nid, 0,
3656 AC_VERB_SET_UNSOLICITED_ENABLE,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003657 (AC_USRSP_EN | event | nid));
3658 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003659}
3660
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003661static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3662{
3663 int i;
3664 for (i = 0; i < cfg->hp_outs; i++)
3665 if (cfg->hp_pins[i] == nid)
3666 return 1; /* nid is a HP-Out */
3667
3668 return 0; /* nid is not a HP-Out */
3669};
3670
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003671static void stac92xx_power_down(struct hda_codec *codec)
3672{
3673 struct sigmatel_spec *spec = codec->spec;
3674
3675 /* power down inactive DACs */
3676 hda_nid_t *dac;
3677 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003678 if (!is_in_dac_nids(spec, *dac) &&
3679 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003680 snd_hda_codec_write_cache(codec, *dac, 0,
3681 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3682}
3683
Mattc7d4b2f2005-06-27 14:59:41 +02003684static int stac92xx_init(struct hda_codec *codec)
3685{
3686 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003687 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay45a6ac12008-10-15 14:45:38 -04003688 int i, err;
Mattc7d4b2f2005-06-27 14:59:41 +02003689
Mattc7d4b2f2005-06-27 14:59:41 +02003690 snd_hda_sequence_write(codec, spec->init);
3691
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003692 /* power down adcs initially */
3693 if (spec->powerdown_adcs)
3694 for (i = 0; i < spec->num_adcs; i++)
3695 snd_hda_codec_write_cache(codec,
3696 spec->adc_nids[i], 0,
3697 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003698 /* set up pins */
3699 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003700 /* Enable unsolicited responses on the HP widget */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003701 for (i = 0; i < cfg->hp_outs; i++) {
3702 int type = SND_JACK_HEADPHONE;
3703 hda_nid_t nid = cfg->hp_pins[i];
3704 enable_pin_detect(codec, nid, STAC_HP_EVENT | nid);
3705 /* jack detection */
3706 if (cfg->hp_outs == i)
3707 type |= SND_JACK_LINEOUT;
3708 err = stac92xx_add_jack(codec, nid, type);
3709 if (err < 0)
3710 return err;
3711
3712 }
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003713 /* force to enable the first line-out; the others are set up
3714 * in unsol_event
3715 */
3716 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003717 AC_PINCTL_OUT_EN);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003718 /* fake event to set up pins */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003719 codec->patch_ops.unsol_event(codec,
3720 (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003721 } else {
3722 stac92xx_auto_init_multi_out(codec);
3723 stac92xx_auto_init_hp_out(codec);
3724 }
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003725 for (i = 0; i < cfg->line_outs; i++) {
3726 err = stac92xx_add_jack(codec,
3727 cfg->line_out_pins[i], SND_JACK_LINEOUT);
3728 if (err < 0)
3729 return err;
3730 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003731 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003732 hda_nid_t nid = cfg->input_pins[i];
3733 if (nid) {
Matthew Ranostayb9aea712008-10-09 08:37:28 -04003734 unsigned int pinctl = snd_hda_codec_read(codec, nid,
3735 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3736 /* if PINCTL already set then skip */
3737 if (pinctl & AC_PINCAP_IN)
3738 continue;
3739 pinctl = AC_PINCTL_IN_EN;
Takashi Iwaic960a032006-03-23 17:06:28 +01003740 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3741 pinctl |= stac92xx_get_vref(codec, nid);
3742 stac92xx_auto_set_pinctl(codec, nid, pinctl);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003743 err = stac92xx_add_jack(codec, nid,
3744 SND_JACK_MICROPHONE);
3745 if (err < 0)
3746 return err;
3747 enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid);
Takashi Iwaic960a032006-03-23 17:06:28 +01003748 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003749 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003750 for (i = 0; i < spec->num_dmics; i++)
3751 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3752 AC_PINCTL_IN_EN);
3753 for (i = 0; i < spec->num_pwrs; i++) {
3754 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3755 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3756 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3757 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003758 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3759 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003760 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003761 /* outputs are only ports capable of power management
3762 * any attempts on powering down a input port cause the
3763 * referenced VREF to act quirky.
3764 */
3765 if (pinctl & AC_PINCTL_IN_EN)
3766 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003767 /* skip any ports that don't have jacks since presence
3768 * detection is useless */
3769 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003770 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003771 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3772 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3773 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003774 if (spec->dac_list)
3775 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003776 if (cfg->dig_out_pin)
3777 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3778 AC_PINCTL_OUT_EN);
3779 if (cfg->dig_in_pin)
3780 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3781 AC_PINCTL_IN_EN);
3782
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003783 stac_gpio_set(codec, spec->gpio_mask,
3784 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003785
Mattc7d4b2f2005-06-27 14:59:41 +02003786 return 0;
3787}
3788
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003789static void stac92xx_free_jacks(struct hda_codec *codec)
3790{
3791 struct sigmatel_spec *spec = codec->spec;
3792 if (spec->jacks.list) {
3793 struct sigmatel_jack *jacks = spec->jacks.list;
3794 int i;
3795 for (i = 0; i < spec->jacks.used; i++)
3796 snd_device_free(codec->bus->card, &jacks[i].jack);
3797 }
3798 snd_array_free(&spec->jacks);
3799}
3800
Takashi Iwai603c4012008-07-30 15:01:44 +02003801static void stac92xx_free_kctls(struct hda_codec *codec)
3802{
3803 struct sigmatel_spec *spec = codec->spec;
3804
3805 if (spec->kctls.list) {
3806 struct snd_kcontrol_new *kctl = spec->kctls.list;
3807 int i;
3808 for (i = 0; i < spec->kctls.used; i++)
3809 kfree(kctl[i].name);
3810 }
3811 snd_array_free(&spec->kctls);
3812}
3813
Matt2f2f4252005-04-13 14:45:30 +02003814static void stac92xx_free(struct hda_codec *codec)
3815{
Mattc7d4b2f2005-06-27 14:59:41 +02003816 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003817
3818 if (! spec)
3819 return;
3820
Richard Fish11b44bb2006-08-23 18:31:34 +02003821 if (spec->bios_pin_configs)
3822 kfree(spec->bios_pin_configs);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003823 stac92xx_free_jacks(codec);
3824 snd_array_free(&spec->events);
Richard Fish11b44bb2006-08-23 18:31:34 +02003825
Mattc7d4b2f2005-06-27 14:59:41 +02003826 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003827 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003828}
3829
Matt4e550962005-07-04 17:51:39 +02003830static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3831 unsigned int flag)
3832{
3833 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3834 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003835
Takashi Iwaif9acba42007-05-29 18:01:06 +02003836 if (pin_ctl & AC_PINCTL_IN_EN) {
3837 /*
3838 * we need to check the current set-up direction of
3839 * shared input pins since they can be switched via
3840 * "xxx as Output" mixer switch
3841 */
3842 struct sigmatel_spec *spec = codec->spec;
3843 struct auto_pin_cfg *cfg = &spec->autocfg;
3844 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3845 spec->line_switch) ||
3846 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3847 spec->mic_switch))
3848 return;
3849 }
3850
Steve Longerbeam7b043892007-05-03 20:50:03 +02003851 /* if setting pin direction bits, clear the current
3852 direction bits first */
3853 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3854 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3855
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003856 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003857 AC_VERB_SET_PIN_WIDGET_CONTROL,
3858 pin_ctl | flag);
3859}
3860
3861static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3862 unsigned int flag)
3863{
3864 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3865 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003866 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003867 AC_VERB_SET_PIN_WIDGET_CONTROL,
3868 pin_ctl & ~flag);
3869}
3870
Jiang Zhe40c1d302007-11-12 13:05:16 +01003871static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003872{
3873 if (!nid)
3874 return 0;
3875 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003876 & (1 << 31)) {
3877 unsigned int pinctl;
3878 pinctl = snd_hda_codec_read(codec, nid, 0,
3879 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3880 if (pinctl & AC_PINCTL_IN_EN)
3881 return 0; /* mic- or line-input */
3882 else
3883 return 1; /* HP-output */
3884 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003885 return 0;
3886}
3887
3888static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003889{
3890 struct sigmatel_spec *spec = codec->spec;
3891 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003892 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003893 int i, presence;
3894
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003895 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003896 if (spec->gpio_mute)
3897 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3898 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3899
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003900 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003901 if (presence)
3902 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003903 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3904 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003905 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003906 }
Matt4e550962005-07-04 17:51:39 +02003907
3908 if (presence) {
3909 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003910 if (spec->hp_switch)
3911 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003912 for (i = 0; i < cfg->line_outs; i++)
3913 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3914 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003915 for (i = 0; i < cfg->speaker_outs; i++)
3916 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3917 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003918 if (spec->eapd_mask)
3919 stac_gpio_set(codec, spec->gpio_mask,
3920 spec->gpio_dir, spec->gpio_data &
3921 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003922 } else {
3923 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003924 if (spec->hp_switch)
3925 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003926 for (i = 0; i < cfg->line_outs; i++)
3927 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3928 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003929 for (i = 0; i < cfg->speaker_outs; i++)
3930 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3931 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003932 if (spec->eapd_mask)
3933 stac_gpio_set(codec, spec->gpio_mask,
3934 spec->gpio_dir, spec->gpio_data |
3935 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003936 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003937 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3938 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003939}
3940
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003941static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3942{
3943 struct sigmatel_spec *spec = codec->spec;
3944 hda_nid_t nid = spec->pwr_nids[idx];
3945 int presence, val;
3946 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3947 & 0x000000ff;
3948 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003949
3950 /* several codecs have two power down bits */
3951 if (spec->pwr_mapping)
3952 idx = spec->pwr_mapping[idx];
3953 else
3954 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003955
3956 if (presence)
3957 val &= ~idx;
3958 else
3959 val |= idx;
3960
3961 /* power down unused output ports */
3962 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003963}
3964
3965static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
3966{
3967 struct sigmatel_spec *spec = codec->spec;
3968 struct sigmatel_jack *jacks = spec->jacks.list;
3969
3970 if (jacks) {
3971 int i;
3972 for (i = 0; i < spec->jacks.used; i++) {
3973 if (jacks->nid == nid) {
3974 unsigned int pin_ctl =
3975 snd_hda_codec_read(codec, nid,
3976 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
3977 0x00);
3978 int type = jacks->type;
3979 if (type == (SND_JACK_LINEOUT
3980 | SND_JACK_HEADPHONE))
3981 type = (pin_ctl & AC_PINCTL_HP_EN)
3982 ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
3983 snd_jack_report(jacks->jack,
3984 get_hp_pin_presence(codec, nid)
3985 ? type : 0);
3986 }
3987 jacks++;
3988 }
3989 }
3990}
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003991
Takashi Iwai314634b2006-09-21 11:56:18 +02003992static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3993{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003994 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003995 int event = (res >> 26) & 0x70;
3996 int nid = res >> 26 & 0x0f;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003997
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003998 switch (event) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003999 case STAC_HP_EVENT:
4000 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004001 /* fallthru */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004002 case STAC_INSERT_EVENT:
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004003 case STAC_PWR_EVENT:
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004004 if (nid) {
4005 if (spec->num_pwrs > 0)
4006 stac92xx_pin_sense(codec, nid);
4007 stac92xx_report_jack(codec, nid);
4008 }
Matthew Ranostay72474be2008-10-09 09:32:17 -04004009 break;
4010 case STAC_VREF_EVENT: {
4011 int data = snd_hda_codec_read(codec, codec->afg, 0,
4012 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004013 int idx = stac92xx_event_data(codec, nid);
Matthew Ranostay72474be2008-10-09 09:32:17 -04004014 /* toggle VREF state based on GPIOx status */
4015 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
4016 !!(data & (1 << idx)));
4017 break;
4018 }
Takashi Iwai314634b2006-09-21 11:56:18 +02004019 }
4020}
4021
Takashi Iwaicb53c622007-08-10 17:21:45 +02004022#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004023static int stac92xx_resume(struct hda_codec *codec)
4024{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004025 struct sigmatel_spec *spec = codec->spec;
4026
Richard Fish11b44bb2006-08-23 18:31:34 +02004027 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004028 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004029 stac_gpio_set(codec, spec->gpio_mask,
4030 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004031 snd_hda_codec_resume_amp(codec);
4032 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004033 /* power down inactive DACs */
4034 if (spec->dac_list)
4035 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004036 /* invoke unsolicited event to reset the HP state */
4037 if (spec->hp_detect)
4038 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02004039 return 0;
4040}
4041#endif
4042
Matt2f2f4252005-04-13 14:45:30 +02004043static struct hda_codec_ops stac92xx_patch_ops = {
4044 .build_controls = stac92xx_build_controls,
4045 .build_pcms = stac92xx_build_pcms,
4046 .init = stac92xx_init,
4047 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02004048 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004049#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004050 .resume = stac92xx_resume,
4051#endif
Matt2f2f4252005-04-13 14:45:30 +02004052};
4053
4054static int patch_stac9200(struct hda_codec *codec)
4055{
4056 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004057 int err;
Matt2f2f4252005-04-13 14:45:30 +02004058
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004059 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004060 if (spec == NULL)
4061 return -ENOMEM;
4062
4063 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004064 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004065 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004066 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
4067 stac9200_models,
4068 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02004069 if (spec->board_config < 0) {
4070 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
4071 err = stac92xx_save_bios_config_regs(codec);
4072 if (err < 0) {
4073 stac92xx_free(codec);
4074 return err;
4075 }
4076 spec->pin_configs = spec->bios_pin_configs;
4077 } else {
Matt Porter403d1942005-11-29 15:00:51 +01004078 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
4079 stac92xx_set_config_regs(codec);
4080 }
Matt2f2f4252005-04-13 14:45:30 +02004081
4082 spec->multiout.max_channels = 2;
4083 spec->multiout.num_dacs = 1;
4084 spec->multiout.dac_nids = stac9200_dac_nids;
4085 spec->adc_nids = stac9200_adc_nids;
4086 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02004087 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02004088 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004089 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004090 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004091
Tobin Davisbf277782008-02-03 20:31:47 +01004092 if (spec->board_config == STAC_9200_GATEWAY ||
4093 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02004094 spec->init = stac9200_eapd_init;
4095 else
4096 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004097 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004098
Takashi Iwai117f2572008-03-18 09:53:23 +01004099 if (spec->board_config == STAC_9200_PANASONIC) {
4100 spec->gpio_mask = spec->gpio_dir = 0x09;
4101 spec->gpio_data = 0x00;
4102 }
4103
Mattc7d4b2f2005-06-27 14:59:41 +02004104 err = stac9200_parse_auto_config(codec);
4105 if (err < 0) {
4106 stac92xx_free(codec);
4107 return err;
4108 }
Matt2f2f4252005-04-13 14:45:30 +02004109
4110 codec->patch_ops = stac92xx_patch_ops;
4111
4112 return 0;
4113}
4114
Tobin Davis8e21c342007-01-08 11:04:17 +01004115static int patch_stac925x(struct hda_codec *codec)
4116{
4117 struct sigmatel_spec *spec;
4118 int err;
4119
4120 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4121 if (spec == NULL)
4122 return -ENOMEM;
4123
4124 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004125 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01004126 spec->pin_nids = stac925x_pin_nids;
4127 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
4128 stac925x_models,
4129 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004130 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01004131 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02004132 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
4133 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01004134 err = stac92xx_save_bios_config_regs(codec);
4135 if (err < 0) {
4136 stac92xx_free(codec);
4137 return err;
4138 }
4139 spec->pin_configs = spec->bios_pin_configs;
4140 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
4141 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
4142 stac92xx_set_config_regs(codec);
4143 }
4144
4145 spec->multiout.max_channels = 2;
4146 spec->multiout.num_dacs = 1;
4147 spec->multiout.dac_nids = stac925x_dac_nids;
4148 spec->adc_nids = stac925x_adc_nids;
4149 spec->mux_nids = stac925x_mux_nids;
4150 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004151 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004152 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02004153 switch (codec->vendor_id) {
4154 case 0x83847632: /* STAC9202 */
4155 case 0x83847633: /* STAC9202D */
4156 case 0x83847636: /* STAC9251 */
4157 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02004158 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02004159 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004160 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
4161 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02004162 break;
4163 default:
4164 spec->num_dmics = 0;
4165 break;
4166 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004167
4168 spec->init = stac925x_core_init;
4169 spec->mixer = stac925x_mixer;
4170
4171 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004172 if (!err) {
4173 if (spec->board_config < 0) {
4174 printk(KERN_WARNING "hda_codec: No auto-config is "
4175 "available, default to model=ref\n");
4176 spec->board_config = STAC_925x_REF;
4177 goto again;
4178 }
4179 err = -EINVAL;
4180 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004181 if (err < 0) {
4182 stac92xx_free(codec);
4183 return err;
4184 }
4185
4186 codec->patch_ops = stac92xx_patch_ops;
4187
4188 return 0;
4189}
4190
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004191static struct hda_input_mux stac92hd73xx_dmux = {
4192 .num_items = 4,
4193 .items = {
4194 { "Analog Inputs", 0x0b },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004195 { "Digital Mic 1", 0x09 },
4196 { "Digital Mic 2", 0x0a },
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004197 { "CD", 0x08 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004198 }
4199};
4200
4201static int patch_stac92hd73xx(struct hda_codec *codec)
4202{
4203 struct sigmatel_spec *spec;
4204 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
4205 int err = 0;
4206
4207 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4208 if (spec == NULL)
4209 return -ENOMEM;
4210
4211 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02004212 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004213 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
4214 spec->pin_nids = stac92hd73xx_pin_nids;
4215 spec->board_config = snd_hda_check_board_config(codec,
4216 STAC_92HD73XX_MODELS,
4217 stac92hd73xx_models,
4218 stac92hd73xx_cfg_tbl);
4219again:
4220 if (spec->board_config < 0) {
4221 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4222 " STAC92HD73XX, using BIOS defaults\n");
4223 err = stac92xx_save_bios_config_regs(codec);
4224 if (err < 0) {
4225 stac92xx_free(codec);
4226 return err;
4227 }
4228 spec->pin_configs = spec->bios_pin_configs;
4229 } else {
4230 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
4231 stac92xx_set_config_regs(codec);
4232 }
4233
4234 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
4235 conn, STAC92HD73_DAC_COUNT + 2) - 1;
4236
4237 if (spec->multiout.num_dacs < 0) {
4238 printk(KERN_WARNING "hda_codec: Could not determine "
4239 "number of channels defaulting to DAC count\n");
4240 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
4241 }
4242
4243 switch (spec->multiout.num_dacs) {
4244 case 0x3: /* 6 Channel */
4245 spec->mixer = stac92hd73xx_6ch_mixer;
4246 spec->init = stac92hd73xx_6ch_core_init;
4247 break;
4248 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004249 spec->mixer = stac92hd73xx_8ch_mixer;
4250 spec->init = stac92hd73xx_8ch_core_init;
4251 break;
4252 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004253 spec->mixer = stac92hd73xx_10ch_mixer;
4254 spec->init = stac92hd73xx_10ch_core_init;
4255 };
4256
4257 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
4258 spec->aloopback_mask = 0x01;
4259 spec->aloopback_shift = 8;
4260
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004261 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004262 spec->mux_nids = stac92hd73xx_mux_nids;
4263 spec->adc_nids = stac92hd73xx_adc_nids;
4264 spec->dmic_nids = stac92hd73xx_dmic_nids;
4265 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004266 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostay89385032008-09-11 09:49:39 -04004267 spec->amp_nids = stac92hd73xx_amp_nids;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004268 spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004269
4270 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
4271 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004272 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004273 memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
4274 sizeof(stac92hd73xx_dmux));
4275
Matthew Ranostaya7662642008-02-21 07:51:14 +01004276 switch (spec->board_config) {
4277 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004278 spec->init = dell_eq_core_init;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004279 spec->num_smuxes = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004280 spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
4281 spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
4282 spec->num_amps = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004283 switch (codec->subsystem_id) {
4284 case 0x1028025e: /* Analog Mics */
4285 case 0x1028025f:
4286 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4287 spec->num_dmics = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004288 spec->private_dimux.num_items = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004289 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01004290 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004291 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004292 spec->init = dell_m6_core_init;
4293 /* fall-through */
4294 case 0x10280254:
4295 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01004296 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4297 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004298 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004299 break;
4300 case 0x10280256: /* Both */
4301 case 0x10280057:
4302 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4303 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4304 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004305 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004306 break;
4307 }
4308 break;
4309 default:
4310 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004311 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaya7662642008-02-21 07:51:14 +01004312 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004313 if (spec->board_config > STAC_92HD73XX_REF) {
4314 /* GPIO0 High = Enable EAPD */
4315 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
4316 spec->gpio_data = 0x01;
4317 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004318 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004319
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004320 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
4321 spec->pwr_nids = stac92hd73xx_pwr_nids;
4322
Matthew Ranostayd9737752008-09-07 12:03:41 +02004323 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004324
4325 if (!err) {
4326 if (spec->board_config < 0) {
4327 printk(KERN_WARNING "hda_codec: No auto-config is "
4328 "available, default to model=ref\n");
4329 spec->board_config = STAC_92HD73XX_REF;
4330 goto again;
4331 }
4332 err = -EINVAL;
4333 }
4334
4335 if (err < 0) {
4336 stac92xx_free(codec);
4337 return err;
4338 }
4339
4340 codec->patch_ops = stac92xx_patch_ops;
4341
4342 return 0;
4343}
4344
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004345static struct hda_input_mux stac92hd83xxx_dmux = {
4346 .num_items = 3,
4347 .items = {
4348 { "Analog Inputs", 0x03 },
4349 { "Digital Mic 1", 0x04 },
4350 { "Digital Mic 2", 0x05 },
4351 }
4352};
4353
4354static int patch_stac92hd83xxx(struct hda_codec *codec)
4355{
4356 struct sigmatel_spec *spec;
4357 int err;
4358
4359 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4360 if (spec == NULL)
4361 return -ENOMEM;
4362
4363 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004364 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004365 spec->mono_nid = 0x19;
4366 spec->digbeep_nid = 0x21;
4367 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4368 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4369 spec->adc_nids = stac92hd83xxx_adc_nids;
4370 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4371 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4372 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4373 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4374
4375 spec->init = stac92hd83xxx_core_init;
4376 switch (codec->vendor_id) {
4377 case 0x111d7605:
4378 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4379 break;
4380 default:
4381 spec->num_pwrs--;
4382 spec->init++; /* switch to config #2 */
4383 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4384 }
4385
4386 spec->mixer = stac92hd83xxx_mixer;
4387 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4388 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4389 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4390 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4391 spec->dinput_mux = &stac92hd83xxx_dmux;
4392 spec->pin_nids = stac92hd83xxx_pin_nids;
4393 spec->board_config = snd_hda_check_board_config(codec,
4394 STAC_92HD83XXX_MODELS,
4395 stac92hd83xxx_models,
4396 stac92hd83xxx_cfg_tbl);
4397again:
4398 if (spec->board_config < 0) {
4399 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4400 " STAC92HD83XXX, using BIOS defaults\n");
4401 err = stac92xx_save_bios_config_regs(codec);
4402 if (err < 0) {
4403 stac92xx_free(codec);
4404 return err;
4405 }
4406 spec->pin_configs = spec->bios_pin_configs;
4407 } else {
4408 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4409 stac92xx_set_config_regs(codec);
4410 }
4411
4412 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4413 if (!err) {
4414 if (spec->board_config < 0) {
4415 printk(KERN_WARNING "hda_codec: No auto-config is "
4416 "available, default to model=ref\n");
4417 spec->board_config = STAC_92HD83XXX_REF;
4418 goto again;
4419 }
4420 err = -EINVAL;
4421 }
4422
4423 if (err < 0) {
4424 stac92xx_free(codec);
4425 return err;
4426 }
4427
4428 codec->patch_ops = stac92xx_patch_ops;
4429
4430 return 0;
4431}
4432
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004433#ifdef SND_HDA_NEEDS_RESUME
4434static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4435{
4436 struct sigmatel_spec *spec = codec->spec;
4437 int i;
4438 snd_hda_codec_write_cache(codec, codec->afg, 0,
4439 AC_VERB_SET_POWER_STATE, pwr);
4440
4441 msleep(1);
4442 for (i = 0; i < spec->num_adcs; i++) {
4443 snd_hda_codec_write_cache(codec,
4444 spec->adc_nids[i], 0,
4445 AC_VERB_SET_POWER_STATE, pwr);
4446 }
4447};
4448
4449static int stac92hd71xx_resume(struct hda_codec *codec)
4450{
4451 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4452 return stac92xx_resume(codec);
4453}
4454
4455static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4456{
4457 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4458 return 0;
4459};
4460
4461#endif
4462
4463static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4464 .build_controls = stac92xx_build_controls,
4465 .build_pcms = stac92xx_build_pcms,
4466 .init = stac92xx_init,
4467 .free = stac92xx_free,
4468 .unsol_event = stac92xx_unsol_event,
4469#ifdef SND_HDA_NEEDS_RESUME
4470 .resume = stac92hd71xx_resume,
4471 .suspend = stac92hd71xx_suspend,
4472#endif
4473};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004474
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004475static struct hda_input_mux stac92hd71bxx_dmux = {
4476 .num_items = 4,
4477 .items = {
4478 { "Analog Inputs", 0x00 },
4479 { "Mixer", 0x01 },
4480 { "Digital Mic 1", 0x02 },
4481 { "Digital Mic 2", 0x03 },
4482 }
4483};
4484
Matthew Ranostaye035b842007-11-06 11:53:55 +01004485static int patch_stac92hd71bxx(struct hda_codec *codec)
4486{
4487 struct sigmatel_spec *spec;
4488 int err = 0;
4489
4490 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4491 if (spec == NULL)
4492 return -ENOMEM;
4493
4494 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004495 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004496 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004497 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004498 spec->pin_nids = stac92hd71bxx_pin_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004499 memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
4500 sizeof(stac92hd71bxx_dmux));
Matthew Ranostaye035b842007-11-06 11:53:55 +01004501 spec->board_config = snd_hda_check_board_config(codec,
4502 STAC_92HD71BXX_MODELS,
4503 stac92hd71bxx_models,
4504 stac92hd71bxx_cfg_tbl);
4505again:
4506 if (spec->board_config < 0) {
4507 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4508 " STAC92HD71BXX, using BIOS defaults\n");
4509 err = stac92xx_save_bios_config_regs(codec);
4510 if (err < 0) {
4511 stac92xx_free(codec);
4512 return err;
4513 }
4514 spec->pin_configs = spec->bios_pin_configs;
4515 } else {
4516 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4517 stac92xx_set_config_regs(codec);
4518 }
4519
Matthew Ranostay541eee82007-12-14 12:08:04 +01004520 switch (codec->vendor_id) {
4521 case 0x111d76b6: /* 4 Port without Analog Mixer */
4522 case 0x111d76b7:
4523 case 0x111d76b4: /* 6 Port without Analog Mixer */
4524 case 0x111d76b5:
4525 spec->mixer = stac92hd71bxx_mixer;
4526 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004527 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004528 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004529 case 0x111d7608: /* 5 Port with Analog Mixer */
Matthew Ranostay72474be2008-10-09 09:32:17 -04004530 switch (codec->subsystem_id) {
4531 case 0x103c361a:
4532 /* Enable VREF power saving on GPIO1 detect */
4533 snd_hda_codec_write(codec, codec->afg, 0,
4534 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4535 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004536 AC_VERB_SET_UNSOLICITED_ENABLE,
4537 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
4538 err = stac92xx_add_event(spec, codec->afg, 0x02);
4539 if (err < 0)
4540 return err;
Matthew Ranostay72474be2008-10-09 09:32:17 -04004541 spec->gpio_mask |= 0x02;
4542 break;
4543 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004544 if ((codec->revision_id & 0xf) == 0 ||
4545 (codec->revision_id & 0xf) == 1) {
4546#ifdef SND_HDA_NEEDS_RESUME
4547 codec->patch_ops = stac92hd71bxx_patch_ops;
4548#endif
4549 spec->stream_delay = 40; /* 40 milliseconds */
4550 }
4551
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004552 /* no output amps */
4553 spec->num_pwrs = 0;
4554 spec->mixer = stac92hd71bxx_analog_mixer;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004555 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004556
4557 /* disable VSW */
4558 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4559 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4560 break;
4561 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004562 if ((codec->revision_id & 0xf) == 1) {
4563#ifdef SND_HDA_NEEDS_RESUME
4564 codec->patch_ops = stac92hd71bxx_patch_ops;
4565#endif
4566 spec->stream_delay = 40; /* 40 milliseconds */
4567 }
4568
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004569 /* no output amps */
4570 spec->num_pwrs = 0;
4571 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004572 default:
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004573 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004574 spec->mixer = stac92hd71bxx_analog_mixer;
4575 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004576 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004577 }
4578
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004579 spec->aloopback_mask = 0x50;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004580 spec->aloopback_shift = 0;
4581
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004582 if (spec->board_config > STAC_92HD71BXX_REF) {
4583 /* GPIO0 = EAPD */
4584 spec->gpio_mask = 0x01;
4585 spec->gpio_dir = 0x01;
4586 spec->gpio_data = 0x01;
4587 }
Matthew Ranostaye035b842007-11-06 11:53:55 +01004588
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004589 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004590 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004591 spec->mux_nids = stac92hd71bxx_mux_nids;
4592 spec->adc_nids = stac92hd71bxx_adc_nids;
4593 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004594 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004595 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004596 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004597
4598 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4599 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004600
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004601 switch (spec->board_config) {
4602 case STAC_HP_M4:
4603 spec->num_dmics = 0;
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004604 spec->num_smuxes = 0;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004605 spec->num_dmuxes = 0;
4606
4607 /* enable internal microphone */
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004608 stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
4609 stac92xx_auto_set_pinctl(codec, 0x0e,
4610 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004611 break;
4612 default:
4613 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4614 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4615 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4616 };
4617
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004618 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004619 spec->multiout.hp_nid = 0x11;
4620 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004621 if (spec->dinput_mux)
4622 spec->private_dimux.num_items +=
4623 spec->num_dmics -
4624 (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004625
4626 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4627 if (!err) {
4628 if (spec->board_config < 0) {
4629 printk(KERN_WARNING "hda_codec: No auto-config is "
4630 "available, default to model=ref\n");
4631 spec->board_config = STAC_92HD71BXX_REF;
4632 goto again;
4633 }
4634 err = -EINVAL;
4635 }
4636
4637 if (err < 0) {
4638 stac92xx_free(codec);
4639 return err;
4640 }
4641
Matthew Ranostaye035b842007-11-06 11:53:55 +01004642 return 0;
4643};
4644
Matt2f2f4252005-04-13 14:45:30 +02004645static int patch_stac922x(struct hda_codec *codec)
4646{
4647 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004648 int err;
Matt2f2f4252005-04-13 14:45:30 +02004649
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004650 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004651 if (spec == NULL)
4652 return -ENOMEM;
4653
4654 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004655 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004656 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004657 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4658 stac922x_models,
4659 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004660 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004661 spec->gpio_mask = spec->gpio_dir = 0x03;
4662 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004663 /* Intel Macs have all same PCI SSID, so we need to check
4664 * codec SSID to distinguish the exact models
4665 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004666 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004667 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004668
4669 case 0x106b0800:
4670 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004671 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004672 case 0x106b0600:
4673 case 0x106b0700:
4674 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004675 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004676 case 0x106b0e00:
4677 case 0x106b0f00:
4678 case 0x106b1600:
4679 case 0x106b1700:
4680 case 0x106b0200:
4681 case 0x106b1e00:
4682 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004683 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004684 case 0x106b1a00:
4685 case 0x00000100:
4686 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004687 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004688 case 0x106b0a00:
4689 case 0x106b2200:
4690 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004691 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004692 default:
4693 spec->board_config = STAC_INTEL_MAC_V3;
4694 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004695 }
4696 }
4697
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004698 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004699 if (spec->board_config < 0) {
4700 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4701 "using BIOS defaults\n");
4702 err = stac92xx_save_bios_config_regs(codec);
4703 if (err < 0) {
4704 stac92xx_free(codec);
4705 return err;
4706 }
4707 spec->pin_configs = spec->bios_pin_configs;
4708 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004709 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4710 stac92xx_set_config_regs(codec);
4711 }
Matt2f2f4252005-04-13 14:45:30 +02004712
Matt2f2f4252005-04-13 14:45:30 +02004713 spec->adc_nids = stac922x_adc_nids;
4714 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004715 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004716 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004717 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004718 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004719
4720 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004721 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004722
4723 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004724
Matt Porter3cc08dc2006-01-23 15:27:49 +01004725 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004726 if (!err) {
4727 if (spec->board_config < 0) {
4728 printk(KERN_WARNING "hda_codec: No auto-config is "
4729 "available, default to model=ref\n");
4730 spec->board_config = STAC_D945_REF;
4731 goto again;
4732 }
4733 err = -EINVAL;
4734 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004735 if (err < 0) {
4736 stac92xx_free(codec);
4737 return err;
4738 }
4739
4740 codec->patch_ops = stac92xx_patch_ops;
4741
Takashi Iwai807a46362007-05-29 19:01:37 +02004742 /* Fix Mux capture level; max to 2 */
4743 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4744 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4745 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4746 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4747 (0 << AC_AMPCAP_MUTE_SHIFT));
4748
Matt Porter3cc08dc2006-01-23 15:27:49 +01004749 return 0;
4750}
4751
4752static int patch_stac927x(struct hda_codec *codec)
4753{
4754 struct sigmatel_spec *spec;
4755 int err;
4756
4757 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4758 if (spec == NULL)
4759 return -ENOMEM;
4760
4761 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004762 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004763 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004764 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4765 stac927x_models,
4766 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004767 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004768 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4769 if (spec->board_config < 0)
4770 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4771 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004772 err = stac92xx_save_bios_config_regs(codec);
4773 if (err < 0) {
4774 stac92xx_free(codec);
4775 return err;
4776 }
4777 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004778 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004779 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4780 stac92xx_set_config_regs(codec);
4781 }
4782
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004783 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004784 spec->adc_nids = stac927x_adc_nids;
4785 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4786 spec->mux_nids = stac927x_mux_nids;
4787 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004788 spec->smux_nids = stac927x_smux_nids;
4789 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04004790 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004791 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004792 spec->multiout.dac_nids = spec->dac_nids;
4793
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004794 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004795 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004796 case STAC_D965_5ST:
4797 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004798 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004799 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004800 spec->num_dmics = 0;
4801
Tobin Davis93ed1502006-09-01 21:03:12 +02004802 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004803 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004804 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004805 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004806 switch (codec->subsystem_id) {
4807 case 0x10280209:
4808 case 0x1028022e:
4809 /* correct the device field to SPDIF out */
4810 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4811 break;
4812 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004813 /* configure the analog microphone on some laptops */
4814 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004815 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004816 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004817 /* correct the front input jack as a mic */
4818 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4819 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004820 case STAC_DELL_3ST:
4821 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004822 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004823 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004824 spec->dmic_nids = stac927x_dmic_nids;
4825 spec->num_dmics = STAC927X_NUM_DMICS;
4826
Tobin Davis93ed1502006-09-01 21:03:12 +02004827 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004828 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004829 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004830 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004831 break;
4832 default:
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004833 if (spec->board_config > STAC_D965_REF) {
4834 /* GPIO0 High = Enable EAPD */
4835 spec->eapd_mask = spec->gpio_mask = 0x01;
4836 spec->gpio_dir = spec->gpio_data = 0x01;
4837 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004838 spec->num_dmics = 0;
4839
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004840 spec->init = stac927x_core_init;
4841 spec->mixer = stac927x_mixer;
4842 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004843
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004844 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004845 spec->aloopback_mask = 0x40;
4846 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004847
Matt Porter3cc08dc2006-01-23 15:27:49 +01004848 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004849 if (!err) {
4850 if (spec->board_config < 0) {
4851 printk(KERN_WARNING "hda_codec: No auto-config is "
4852 "available, default to model=ref\n");
4853 spec->board_config = STAC_D965_REF;
4854 goto again;
4855 }
4856 err = -EINVAL;
4857 }
Mattc7d4b2f2005-06-27 14:59:41 +02004858 if (err < 0) {
4859 stac92xx_free(codec);
4860 return err;
4861 }
Matt2f2f4252005-04-13 14:45:30 +02004862
4863 codec->patch_ops = stac92xx_patch_ops;
4864
Takashi Iwai52987652008-01-16 16:09:47 +01004865 /*
4866 * !!FIXME!!
4867 * The STAC927x seem to require fairly long delays for certain
4868 * command sequences. With too short delays (even if the answer
4869 * is set to RIRB properly), it results in the silence output
4870 * on some hardwares like Dell.
4871 *
4872 * The below flag enables the longer delay (see get_response
4873 * in hda_intel.c).
4874 */
4875 codec->bus->needs_damn_long_delay = 1;
4876
Matt2f2f4252005-04-13 14:45:30 +02004877 return 0;
4878}
4879
Matt Porterf3302a52006-07-31 12:49:34 +02004880static int patch_stac9205(struct hda_codec *codec)
4881{
4882 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004883 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004884
4885 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4886 if (spec == NULL)
4887 return -ENOMEM;
4888
4889 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004890 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004891 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004892 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4893 stac9205_models,
4894 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004895 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004896 if (spec->board_config < 0) {
4897 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4898 err = stac92xx_save_bios_config_regs(codec);
4899 if (err < 0) {
4900 stac92xx_free(codec);
4901 return err;
4902 }
4903 spec->pin_configs = spec->bios_pin_configs;
4904 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004905 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4906 stac92xx_set_config_regs(codec);
4907 }
4908
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004909 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004910 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004911 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004912 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004913 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004914 spec->smux_nids = stac9205_smux_nids;
4915 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004916 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004917 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004918 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004919 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004920 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004921
4922 spec->init = stac9205_core_init;
4923 spec->mixer = stac9205_mixer;
4924
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004925 spec->aloopback_mask = 0x40;
4926 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004927 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004928
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004929 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004930 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004931 /* Enable SPDIF in/out */
4932 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4933 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004934
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004935 /* Enable unsol response for GPIO4/Dock HP connection */
4936 snd_hda_codec_write(codec, codec->afg, 0,
4937 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4938 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004939 AC_VERB_SET_UNSOLICITED_ENABLE,
4940 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
4941 err = stac92xx_add_event(spec, codec->afg, 0x01);
4942 if (err < 0)
4943 return err;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004944
4945 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004946 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004947 spec->gpio_mask = 0x1b;
4948 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004949 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004950 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004951 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004952 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004953 break;
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004954 case STAC_9205_REF:
4955 /* SPDIF-In enabled */
4956 break;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004957 default:
4958 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004959 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004960 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004961 break;
4962 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004963
Matt Porterf3302a52006-07-31 12:49:34 +02004964 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004965 if (!err) {
4966 if (spec->board_config < 0) {
4967 printk(KERN_WARNING "hda_codec: No auto-config is "
4968 "available, default to model=ref\n");
4969 spec->board_config = STAC_9205_REF;
4970 goto again;
4971 }
4972 err = -EINVAL;
4973 }
Matt Porterf3302a52006-07-31 12:49:34 +02004974 if (err < 0) {
4975 stac92xx_free(codec);
4976 return err;
4977 }
4978
4979 codec->patch_ops = stac92xx_patch_ops;
4980
4981 return 0;
4982}
4983
Matt2f2f4252005-04-13 14:45:30 +02004984/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004985 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004986 */
4987
Guillaume Munch99ccc562006-08-16 19:35:12 +02004988/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004989static hda_nid_t vaio_dacs[] = { 0x2 };
4990#define VAIO_HP_DAC 0x5
4991static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4992static hda_nid_t vaio_mux_nids[] = { 0x15 };
4993
4994static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004995 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004996 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004997 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004998 { "Mic Jack", 0x1 },
4999 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01005000 { "PCM", 0x3 },
5001 }
5002};
5003
5004static struct hda_verb vaio_init[] = {
5005 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005006 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01005007 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5008 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5009 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5010 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005011 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005012 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5013 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5014 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5015 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5016 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5017 {}
5018};
5019
Guillaume Munch6d859062006-08-22 17:15:47 +02005020static struct hda_verb vaio_ar_init[] = {
5021 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
5022 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5023 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5024 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5025/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
5026 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005027 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02005028 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5029 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5030/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
5031 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5032 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5033 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5034 {}
5035};
5036
Takashi Iwaidb064e52006-03-16 16:04:58 +01005037/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02005038static struct hda_bind_ctls vaio_bind_master_vol = {
5039 .ops = &snd_hda_bind_vol,
5040 .values = {
5041 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
5042 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
5043 0
5044 },
5045};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005046
5047/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02005048static struct hda_bind_ctls vaio_bind_master_sw = {
5049 .ops = &snd_hda_bind_sw,
5050 .values = {
5051 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
5052 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
5053 0,
5054 },
5055};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005056
5057static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02005058 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
5059 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005060 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5061 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5062 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5063 {
5064 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5065 .name = "Capture Source",
5066 .count = 1,
5067 .info = stac92xx_mux_enum_info,
5068 .get = stac92xx_mux_enum_get,
5069 .put = stac92xx_mux_enum_put,
5070 },
5071 {}
5072};
5073
Guillaume Munch6d859062006-08-22 17:15:47 +02005074static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02005075 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
5076 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02005077 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5078 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5079 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5080 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
5081 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
5082 {
5083 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5084 .name = "Capture Source",
5085 .count = 1,
5086 .info = stac92xx_mux_enum_info,
5087 .get = stac92xx_mux_enum_get,
5088 .put = stac92xx_mux_enum_put,
5089 },
5090 {}
5091};
5092
5093static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01005094 .build_controls = stac92xx_build_controls,
5095 .build_pcms = stac92xx_build_pcms,
5096 .init = stac92xx_init,
5097 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005098#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01005099 .resume = stac92xx_resume,
5100#endif
5101};
5102
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005103static int stac9872_vaio_init(struct hda_codec *codec)
5104{
5105 int err;
5106
5107 err = stac92xx_init(codec);
5108 if (err < 0)
5109 return err;
5110 if (codec->patch_ops.unsol_event)
5111 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
5112 return 0;
5113}
5114
5115static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
5116{
Jiang Zhe40c1d302007-11-12 13:05:16 +01005117 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005118 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5119 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5120 } else {
5121 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5122 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5123 }
5124}
5125
5126static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
5127{
5128 switch (res >> 26) {
5129 case STAC_HP_EVENT:
5130 stac9872_vaio_hp_detect(codec, res);
5131 break;
5132 }
5133}
5134
5135static struct hda_codec_ops stac9872_vaio_patch_ops = {
5136 .build_controls = stac92xx_build_controls,
5137 .build_pcms = stac92xx_build_pcms,
5138 .init = stac9872_vaio_init,
5139 .free = stac92xx_free,
5140 .unsol_event = stac9872_vaio_unsol_event,
5141#ifdef CONFIG_PM
5142 .resume = stac92xx_resume,
5143#endif
5144};
5145
Guillaume Munch6d859062006-08-22 17:15:47 +02005146enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
5147 CXD9872RD_VAIO,
5148 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
5149 STAC9872AK_VAIO,
5150 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
5151 STAC9872K_VAIO,
5152 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005153 CXD9872AKD_VAIO,
5154 STAC_9872_MODELS,
5155};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005156
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005157static const char *stac9872_models[STAC_9872_MODELS] = {
5158 [CXD9872RD_VAIO] = "vaio",
5159 [CXD9872AKD_VAIO] = "vaio-ar",
5160};
5161
5162static struct snd_pci_quirk stac9872_cfg_tbl[] = {
5163 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
5164 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
5165 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01005166 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005167 {}
5168};
5169
Guillaume Munch6d859062006-08-22 17:15:47 +02005170static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01005171{
5172 struct sigmatel_spec *spec;
5173 int board_config;
5174
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005175 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
5176 stac9872_models,
5177 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01005178 if (board_config < 0)
5179 /* unknown config, let generic-parser do its job... */
5180 return snd_hda_parse_generic_codec(codec);
5181
5182 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5183 if (spec == NULL)
5184 return -ENOMEM;
5185
5186 codec->spec = spec;
5187 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02005188 case CXD9872RD_VAIO:
5189 case STAC9872AK_VAIO:
5190 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01005191 spec->mixer = vaio_mixer;
5192 spec->init = vaio_init;
5193 spec->multiout.max_channels = 2;
5194 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5195 spec->multiout.dac_nids = vaio_dacs;
5196 spec->multiout.hp_nid = VAIO_HP_DAC;
5197 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
5198 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005199 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005200 spec->input_mux = &vaio_mux;
5201 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005202 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005203 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02005204
5205 case CXD9872AKD_VAIO:
5206 spec->mixer = vaio_ar_mixer;
5207 spec->init = vaio_ar_init;
5208 spec->multiout.max_channels = 2;
5209 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5210 spec->multiout.dac_nids = vaio_dacs;
5211 spec->multiout.hp_nid = VAIO_HP_DAC;
5212 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005213 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02005214 spec->adc_nids = vaio_adcs;
5215 spec->input_mux = &vaio_mux;
5216 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005217 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02005218 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005219 }
5220
Takashi Iwaidb064e52006-03-16 16:04:58 +01005221 return 0;
5222}
5223
5224
5225/*
Matt2f2f4252005-04-13 14:45:30 +02005226 * patch entries
5227 */
5228struct hda_codec_preset snd_hda_preset_sigmatel[] = {
5229 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
5230 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
5231 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
5232 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
5233 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
5234 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
5235 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02005236 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
5237 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
5238 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
5239 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
5240 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
5241 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01005242 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
5243 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
5244 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
5245 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
5246 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
5247 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
5248 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
5249 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
5250 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
5251 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01005252 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
5253 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
5254 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
5255 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
5256 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
5257 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02005258 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
5259 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02005260 /* The following does not take into account .id=0x83847661 when subsys =
5261 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
5262 * currently not fully supported.
5263 */
5264 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
5265 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
5266 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02005267 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
5268 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
5269 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
5270 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
5271 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
5272 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
5273 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
5274 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005275 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005276 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
5277 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005278 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01005279 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
5280 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005281 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01005282 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5283 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5284 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5285 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5286 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5287 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5288 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
5289 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02005290 {} /* terminator */
5291};