blob: 35b83dc6e19e5922104f5319302f7e7fa0376d73 [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"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020036#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020037
Takashi Iwaic6e4c662008-11-25 11:58:19 +010038enum {
39 STAC_VREF_EVENT = 1,
40 STAC_INSERT_EVENT,
41 STAC_PWR_EVENT,
42 STAC_HP_EVENT,
43};
Matt4e550962005-07-04 17:51:39 +020044
Takashi Iwaif5fcc132006-11-24 17:07:44 +010045enum {
46 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010047 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020048 STAC_9200_DELL_D21,
49 STAC_9200_DELL_D22,
50 STAC_9200_DELL_D23,
51 STAC_9200_DELL_M21,
52 STAC_9200_DELL_M22,
53 STAC_9200_DELL_M23,
54 STAC_9200_DELL_M24,
55 STAC_9200_DELL_M25,
56 STAC_9200_DELL_M26,
57 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020058 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010059 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010060 STAC_9200_MODELS
61};
62
63enum {
64 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020065 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020066 STAC_9205_DELL_M43,
67 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010068 STAC_9205_MODELS
69};
70
71enum {
Takashi Iwai9e43f0d2008-12-17 14:51:01 +010072 STAC_92HD73XX_NO_JD, /* no jack-detection */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010073 STAC_92HD73XX_REF,
Takashi Iwai661cd8f2008-11-25 15:18:29 +010074 STAC_DELL_M6_AMIC,
75 STAC_DELL_M6_DMIC,
76 STAC_DELL_M6_BOTH,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -050077 STAC_DELL_EQ,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010078 STAC_92HD73XX_MODELS
79};
80
81enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020082 STAC_92HD83XXX_REF,
83 STAC_92HD83XXX_MODELS
84};
85
86enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010087 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010088 STAC_DELL_M4_1,
89 STAC_DELL_M4_2,
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -050090 STAC_DELL_M4_3,
Matthew Ranostay6a14f582008-09-12 12:02:30 -040091 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010092 STAC_92HD71BXX_MODELS
93};
94
95enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010096 STAC_925x_REF,
97 STAC_M2_2,
98 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020099 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +0100100 STAC_925x_MODELS
101};
102
103enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100104 STAC_D945_REF,
105 STAC_D945GTP3,
106 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200107 STAC_INTEL_MAC_V1,
108 STAC_INTEL_MAC_V2,
109 STAC_INTEL_MAC_V3,
110 STAC_INTEL_MAC_V4,
111 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800112 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
113 * is given, one of the above models will be
114 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200115 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100116 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100117 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100118 STAC_MACBOOK_PRO_V1,
119 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200120 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200121 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300122 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200123 STAC_922X_DELL_D81,
124 STAC_922X_DELL_D82,
125 STAC_922X_DELL_M81,
126 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100127 STAC_922X_MODELS
128};
129
130enum {
Takashi Iwaie28d8322008-12-17 13:48:29 +0100131 STAC_D965_REF_NO_JD, /* no jack-detection */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100132 STAC_D965_REF,
133 STAC_D965_3ST,
134 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200135 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100136 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100137 STAC_927X_MODELS
138};
Matt Porter403d1942005-11-29 15:00:51 +0100139
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400140struct sigmatel_event {
141 hda_nid_t nid;
Takashi Iwaic6e4c662008-11-25 11:58:19 +0100142 unsigned char type;
143 unsigned char tag;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400144 int data;
145};
146
147struct sigmatel_jack {
148 hda_nid_t nid;
149 int type;
150 struct snd_jack *jack;
151};
152
Matt2f2f4252005-04-13 14:45:30 +0200153struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100154 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200155 unsigned int num_mixers;
156
Matt Porter403d1942005-11-29 15:00:51 +0100157 int board_config;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -0500158 unsigned int eapd_switch: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200159 unsigned int surr_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100160 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100161 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400162 unsigned int spdif_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200163
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100164 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200165 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100166 unsigned int gpio_mask;
167 unsigned int gpio_dir;
168 unsigned int gpio_data;
169 unsigned int gpio_mute;
170
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200171 /* stream */
172 unsigned int stream_delay;
173
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100174 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100175 unsigned char aloopback_mask;
176 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200177
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100178 /* power management */
179 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200180 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100181 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100182 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100183
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400184 /* jack detection */
185 struct snd_array jacks;
186
187 /* events */
188 struct snd_array events;
189
Matt2f2f4252005-04-13 14:45:30 +0200190 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100191 struct hda_input_mux *mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400192 struct hda_input_mux *amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100193 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200194 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100195 hda_nid_t dac_nids[5];
Takashi Iwaic21ca4a2008-12-19 09:26:08 +0100196 hda_nid_t hp_dacs[5];
197 hda_nid_t speaker_dacs[5];
Matt2f2f4252005-04-13 14:45:30 +0200198
199 /* capture */
200 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200201 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200202 hda_nid_t *mux_nids;
203 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200204 hda_nid_t *dmic_nids;
205 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100206 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100207 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200208 hda_nid_t *smux_nids;
209 unsigned int num_smuxes;
Matthew Ranostay65973632008-09-16 10:39:37 -0400210 const char **spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200211
Mattdabbed62005-06-14 10:19:34 +0200212 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100213 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200214 hda_nid_t anabeep_nid;
215 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200216
Matt2f2f4252005-04-13 14:45:30 +0200217 /* pin widgets */
218 hda_nid_t *pin_nids;
219 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200220 unsigned int *pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200221
222 /* codec specific stuff */
223 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100224 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200225
226 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200227 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100228 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200229 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100230 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200231 struct hda_input_mux *sinput_mux;
232 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400233 unsigned int cur_amux;
234 hda_nid_t *amp_nids;
235 unsigned int num_amps;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200236 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200237
Matt Porter403d1942005-11-29 15:00:51 +0100238 /* i/o switches */
239 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200240 unsigned int clfe_swap;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +0100241 hda_nid_t line_switch; /* shared line-in for input and output */
242 hda_nid_t mic_switch; /* shared mic-in for input and output */
243 hda_nid_t hp_switch; /* NID of HP as line-out */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200244 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200245
Mattc7d4b2f2005-06-27 14:59:41 +0200246 struct hda_pcm pcm_rec[2]; /* PCM information */
247
248 /* dynamic controls and input_mux */
249 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200250 struct snd_array kctls;
Matt Porter8b657272006-10-26 17:12:59 +0200251 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200252 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200253 struct hda_input_mux private_smux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400254 struct hda_input_mux private_amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100255 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200256};
257
258static hda_nid_t stac9200_adc_nids[1] = {
259 0x03,
260};
261
262static hda_nid_t stac9200_mux_nids[1] = {
263 0x0c,
264};
265
266static hda_nid_t stac9200_dac_nids[1] = {
267 0x02,
268};
269
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100270static hda_nid_t stac92hd73xx_pwr_nids[8] = {
271 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
272 0x0f, 0x10, 0x11
273};
274
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400275static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
276 0x26, 0,
277};
278
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100279static hda_nid_t stac92hd73xx_adc_nids[2] = {
280 0x1a, 0x1b
281};
282
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400283#define DELL_M6_AMP 2
284static hda_nid_t stac92hd73xx_amp_nids[3] = {
285 0x0b, 0x0c, 0x0e
Matthew Ranostay89385032008-09-11 09:49:39 -0400286};
287
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100288#define STAC92HD73XX_NUM_DMICS 2
289static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
290 0x13, 0x14, 0
291};
292
293#define STAC92HD73_DAC_COUNT 5
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100294
295static hda_nid_t stac92hd73xx_mux_nids[4] = {
296 0x28, 0x29, 0x2a, 0x2b,
297};
298
299static hda_nid_t stac92hd73xx_dmux_nids[2] = {
300 0x20, 0x21,
301};
302
Matthew Ranostayd9737752008-09-07 12:03:41 +0200303static hda_nid_t stac92hd73xx_smux_nids[2] = {
304 0x22, 0x23,
305};
306
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200307#define STAC92HD83XXX_NUM_DMICS 2
308static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
309 0x11, 0x12, 0
310};
311
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200312#define STAC92HD83_DAC_COUNT 3
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200313
314static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
315 0x17, 0x18,
316};
317
318static hda_nid_t stac92hd83xxx_adc_nids[2] = {
319 0x15, 0x16,
320};
321
322static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
323 0xa, 0xb, 0xd, 0xe,
324};
325
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400326static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
327 0x1e, 0,
328};
329
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200330static unsigned int stac92hd83xxx_pwr_mapping[4] = {
331 0x03, 0x0c, 0x10, 0x40,
332};
333
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100334static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
335 0x0a, 0x0d, 0x0f
336};
337
Matthew Ranostaye035b842007-11-06 11:53:55 +0100338static hda_nid_t stac92hd71bxx_adc_nids[2] = {
339 0x12, 0x13,
340};
341
342static hda_nid_t stac92hd71bxx_mux_nids[2] = {
343 0x1a, 0x1b
344};
345
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400346static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
347 0x1c, 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100348};
349
Matthew Ranostayd9737752008-09-07 12:03:41 +0200350static hda_nid_t stac92hd71bxx_smux_nids[2] = {
351 0x24, 0x25,
352};
353
Matthew Ranostaye035b842007-11-06 11:53:55 +0100354#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)
Takashi Iwaic9b46f92008-12-01 11:42:09 +0100585 val = HDA_AMP_MUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400586 else
Takashi Iwaic9b46f92008-12-01 11:42:09 +0100587 val = 0;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400588 /* un/mute SPDIF out */
Takashi Iwaic9b46f92008-12-01 11:42:09 +0100589 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
590 HDA_AMP_MUTE, val);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400591 }
592 return 0;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200593}
594
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100595static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200596{
597 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
598 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200599 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200600}
601
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100602static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200603{
604 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
605 struct sigmatel_spec *spec = codec->spec;
606 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
607
608 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
609 return 0;
610}
611
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100612static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200613{
614 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
615 struct sigmatel_spec *spec = codec->spec;
616 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
617
Mattc7d4b2f2005-06-27 14:59:41 +0200618 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200619 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
620}
621
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100622static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
623 struct snd_ctl_elem_info *uinfo)
624{
625 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
626 struct sigmatel_spec *spec = codec->spec;
627 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
628}
629
630static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
631 struct snd_ctl_elem_value *ucontrol)
632{
633 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
634 struct sigmatel_spec *spec = codec->spec;
635
636 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
637 return 0;
638}
639
640static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
641 struct snd_ctl_elem_value *ucontrol)
642{
643 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
644 struct sigmatel_spec *spec = codec->spec;
645
646 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
647 spec->mono_nid, &spec->cur_mmux);
648}
649
Matthew Ranostay89385032008-09-11 09:49:39 -0400650static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
651 struct snd_ctl_elem_info *uinfo)
652{
653 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
654 struct sigmatel_spec *spec = codec->spec;
655 return snd_hda_input_mux_info(spec->amp_mux, uinfo);
656}
657
658static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
659 struct snd_ctl_elem_value *ucontrol)
660{
661 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
662 struct sigmatel_spec *spec = codec->spec;
663
664 ucontrol->value.enumerated.item[0] = spec->cur_amux;
665 return 0;
666}
667
668static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
669 struct snd_ctl_elem_value *ucontrol)
670{
671 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
672 struct sigmatel_spec *spec = codec->spec;
673 struct snd_kcontrol *ctl =
674 snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
675 if (!ctl)
676 return -EINVAL;
677
678 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
679 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
680
681 return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
682 0, &spec->cur_amux);
683}
684
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200685#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
686
687static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
688 struct snd_ctl_elem_value *ucontrol)
689{
690 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100691 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200692 struct sigmatel_spec *spec = codec->spec;
693
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100694 ucontrol->value.integer.value[0] = !!(spec->aloopback &
695 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200696 return 0;
697}
698
699static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
700 struct snd_ctl_elem_value *ucontrol)
701{
702 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
703 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100704 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200705 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100706 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200707
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100708 idx_val = spec->aloopback_mask << idx;
709 if (ucontrol->value.integer.value[0])
710 val = spec->aloopback | idx_val;
711 else
712 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100713 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200714 return 0;
715
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100716 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200717
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100718 /* Only return the bits defined by the shift value of the
719 * first two bytes of the mask
720 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200721 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100722 kcontrol->private_value & 0xFFFF, 0x0);
723 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200724
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100725 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200726 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100727 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200728 } else {
729 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100730 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200731 }
732
733 snd_hda_codec_write_cache(codec, codec->afg, 0,
734 kcontrol->private_value >> 16, dac_mode);
735
736 return 1;
737}
738
Mattc7d4b2f2005-06-27 14:59:41 +0200739static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200740 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200741 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200742 {}
743};
744
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200745static struct hda_verb stac9200_eapd_init[] = {
746 /* set dac0mux for dac converter */
747 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
748 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
749 {}
750};
751
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100752static struct hda_verb stac92hd73xx_6ch_core_init[] = {
753 /* set master volume and direct control */
754 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100755 /* setup adcs to point to mixer */
756 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
757 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100758 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
759 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
760 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
761 /* setup import muxs */
762 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
763 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
764 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
765 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
766 {}
767};
768
Matthew Ranostayd654a662008-03-14 08:46:51 +0100769static struct hda_verb dell_eq_core_init[] = {
770 /* set master volume to max value without distortion
771 * and direct control */
772 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostayd654a662008-03-14 08:46:51 +0100773 /* setup adcs to point to mixer */
774 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
775 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
776 /* setup import muxs */
777 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
778 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
779 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
780 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
781 {}
782};
783
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100784static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -0500785 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100786 /* setup adcs to point to mixer */
787 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
788 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
789 /* setup import muxs */
790 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
791 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
792 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
793 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
794 {}
795};
796
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100797static struct hda_verb stac92hd73xx_8ch_core_init[] = {
798 /* set master volume and direct control */
799 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100800 /* setup adcs to point to mixer */
801 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
802 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100803 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
804 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
805 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
806 /* setup import muxs */
807 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
808 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
809 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
810 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
811 {}
812};
813
814static struct hda_verb stac92hd73xx_10ch_core_init[] = {
815 /* set master volume and direct control */
816 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100817 /* dac3 is connected to import3 mux */
818 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100819 /* setup adcs to point to mixer */
820 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
821 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100822 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
823 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
824 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
825 /* setup import muxs */
826 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
827 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
828 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
829 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
830 {}
831};
832
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200833static struct hda_verb stac92hd83xxx_core_init[] = {
834 /* start of config #1 */
835 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
836
837 /* start of config #2 */
838 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
839 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
840 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
841
842 /* power state controls amps */
843 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
Herton Ronaldo Krzesinski574f3c42008-12-23 16:53:00 -0200844 {}
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200845};
846
Matthew Ranostaye035b842007-11-06 11:53:55 +0100847static struct hda_verb stac92hd71bxx_core_init[] = {
848 /* set master volume and direct control */
849 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100850 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
851 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
852 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
853 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Herton Ronaldo Krzesinski574f3c42008-12-23 16:53:00 -0200854 {}
Matthew Ranostay541eee82007-12-14 12:08:04 +0100855};
856
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400857#define HD_DISABLE_PORTF 2
Matthew Ranostay541eee82007-12-14 12:08:04 +0100858static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200859 /* start of config #1 */
860
861 /* connect port 0f to audio mixer */
862 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200863 /* unmute right and left channels for node 0x0f */
864 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
865 /* start of config #2 */
866
Matthew Ranostay541eee82007-12-14 12:08:04 +0100867 /* set master volume and direct control */
868 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200869 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100870 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
871 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100872 {}
873};
874
Tobin Davis8e21c342007-01-08 11:04:17 +0100875static struct hda_verb stac925x_core_init[] = {
876 /* set dac0mux for dac converter */
877 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
878 {}
879};
880
Mattc7d4b2f2005-06-27 14:59:41 +0200881static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200882 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200883 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200884 {}
885};
886
Tobin Davis93ed1502006-09-01 21:03:12 +0200887static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200888 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200889 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200890 /* unmute node 0x1b */
891 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
892 /* select node 0x03 as DAC */
893 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
894 {}
895};
896
Matt Porter3cc08dc2006-01-23 15:27:49 +0100897static struct hda_verb stac927x_core_init[] = {
898 /* set master volume and direct control */
899 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200900 /* enable analog pc beep path */
901 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100902 {}
903};
904
Matt Porterf3302a52006-07-31 12:49:34 +0200905static struct hda_verb stac9205_core_init[] = {
906 /* set master volume and direct control */
907 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200908 /* enable analog pc beep path */
909 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200910 {}
911};
912
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100913#define STAC_MONO_MUX \
914 { \
915 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
916 .name = "Mono Mux", \
917 .count = 1, \
918 .info = stac92xx_mono_mux_enum_info, \
919 .get = stac92xx_mono_mux_enum_get, \
920 .put = stac92xx_mono_mux_enum_put, \
921 }
922
Matthew Ranostay89385032008-09-11 09:49:39 -0400923#define STAC_AMP_MUX \
924 { \
925 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
926 .name = "Amp Selector Capture Switch", \
927 .count = 1, \
928 .info = stac92xx_amp_mux_enum_info, \
929 .get = stac92xx_amp_mux_enum_get, \
930 .put = stac92xx_amp_mux_enum_put, \
931 }
932
933#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
934 { \
935 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
936 .name = xname, \
937 .index = 0, \
938 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
939 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
940 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
941 .info = stac92xx_amp_volume_info, \
942 .get = stac92xx_amp_volume_get, \
943 .put = stac92xx_amp_volume_put, \
944 .tlv = { .c = snd_hda_mixer_amp_tlv }, \
945 .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
946 }
947
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200948#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200949 { \
950 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
951 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200952 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200953 .info = stac92xx_mux_enum_info, \
954 .get = stac92xx_mux_enum_get, \
955 .put = stac92xx_mux_enum_put, \
956 }
957
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100958#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200959 { \
960 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
961 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100962 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200963 .info = stac92xx_aloopback_info, \
964 .get = stac92xx_aloopback_get, \
965 .put = stac92xx_aloopback_put, \
966 .private_value = verb_read | (verb_write << 16), \
967 }
968
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100969static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200970 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
971 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200972 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200973 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
974 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200975 { } /* end */
976};
977
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400978#define DELL_M6_MIXER 6
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100979static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400980 /* start of config #1 */
981 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
982 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
983
984 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
985 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
986
987 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
988 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
989
990 /* start of config #2 */
991 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
992 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
993
994 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
995 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
996
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100997 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
998
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100999 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1000 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1001
1002 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1003 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1004
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001005 { } /* end */
1006};
1007
1008static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001009 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1010
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001011 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1012 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1013
1014 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1015 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1016
1017 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1018 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1019
1020 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1021 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1022
1023 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1024 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, 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
1029 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1030 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1031 { } /* end */
1032};
1033
1034static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001035 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1036
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001037 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1038 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1039
1040 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1041 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1042
1043 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1044 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1045
1046 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1047 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1048
1049 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1050 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1051
1052 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1053 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1054
1055 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1056 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1057 { } /* end */
1058};
1059
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001060
1061static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
1062 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
1063 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
1064
1065 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
1066 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
1067
Matthew Ranostay74b7ff42008-12-20 17:47:24 -05001068 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT),
1069 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT),
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001070
Matthew Ranostay74b7ff42008-12-20 17:47:24 -05001071 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT),
1072 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT),
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001073
Matthew Ranostay74b7ff42008-12-20 17:47:24 -05001074 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT),
1075 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT),
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001076
Matthew Ranostay74b7ff42008-12-20 17:47:24 -05001077 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT),
1078 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT),
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001079
1080 /*
Matthew Ranostay74b7ff42008-12-20 17:47:24 -05001081 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT),
1082 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT),
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001083 */
1084 { } /* end */
1085};
1086
Matthew Ranostay541eee82007-12-14 12:08:04 +01001087static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001088 STAC_INPUT_SOURCE(2),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001089 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001090
Matthew Ranostay9b359472007-11-07 13:03:12 +01001091 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1092 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +01001093
1094 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1095 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001096 /* analog pc-beep replaced with digital beep support */
1097 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001098 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
1099 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001100 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001101
Matthew Ranostay687cb982008-10-11 13:52:43 -04001102 HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
1103 HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001104
Matthew Ranostay687cb982008-10-11 13:52:43 -04001105 HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
1106 HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001107
1108 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
1109 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
1110
1111 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
1112 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001113 { } /* end */
1114};
1115
Matthew Ranostay541eee82007-12-14 12:08:04 +01001116static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +01001117 STAC_INPUT_SOURCE(2),
1118 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
1119
Matthew Ranostay541eee82007-12-14 12:08:04 +01001120 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1121 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001122
1123 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1124 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001125 { } /* end */
1126};
1127
Tobin Davis8e21c342007-01-08 11:04:17 +01001128static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001129 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001130 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001131 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001132 { } /* end */
1133};
1134
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001135static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001136 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001137 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001138
1139 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1140 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001141
1142 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1143 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001144 { } /* end */
1145};
1146
1147/* This needs to be generated dynamically based on sequence */
1148static struct snd_kcontrol_new stac922x_mixer[] = {
1149 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001150 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1151 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001152
1153 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1154 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001155 { } /* end */
1156};
1157
1158
1159static struct snd_kcontrol_new stac927x_mixer[] = {
1160 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001161 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001162
1163 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1164 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001165
1166 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1167 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001168
1169 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1170 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001171 { } /* end */
1172};
1173
Takashi Iwai1697055e2007-12-18 18:05:52 +01001174static struct snd_kcontrol_new stac_dmux_mixer = {
1175 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1176 .name = "Digital Input Source",
1177 /* count set later */
1178 .info = stac92xx_dmux_enum_info,
1179 .get = stac92xx_dmux_enum_get,
1180 .put = stac92xx_dmux_enum_put,
1181};
1182
Matthew Ranostayd9737752008-09-07 12:03:41 +02001183static struct snd_kcontrol_new stac_smux_mixer = {
1184 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001185 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001186 /* count set later */
1187 .info = stac92xx_smux_enum_info,
1188 .get = stac92xx_smux_enum_get,
1189 .put = stac92xx_smux_enum_put,
1190};
1191
Takashi Iwai2134ea42008-01-10 16:53:55 +01001192static const char *slave_vols[] = {
1193 "Front Playback Volume",
1194 "Surround Playback Volume",
1195 "Center Playback Volume",
1196 "LFE Playback Volume",
1197 "Side Playback Volume",
1198 "Headphone Playback Volume",
1199 "Headphone Playback Volume",
1200 "Speaker Playback Volume",
1201 "External Speaker Playback Volume",
1202 "Speaker2 Playback Volume",
1203 NULL
1204};
1205
1206static const char *slave_sws[] = {
1207 "Front Playback Switch",
1208 "Surround Playback Switch",
1209 "Center Playback Switch",
1210 "LFE Playback Switch",
1211 "Side Playback Switch",
1212 "Headphone Playback Switch",
1213 "Headphone Playback Switch",
1214 "Speaker Playback Switch",
1215 "External Speaker Playback Switch",
1216 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001217 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001218 NULL
1219};
1220
Takashi Iwai603c4012008-07-30 15:01:44 +02001221static void stac92xx_free_kctls(struct hda_codec *codec);
Takashi Iwaie4973e12008-11-18 09:32:42 +01001222static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
Takashi Iwai603c4012008-07-30 15:01:44 +02001223
Matt2f2f4252005-04-13 14:45:30 +02001224static int stac92xx_build_controls(struct hda_codec *codec)
1225{
1226 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaie4973e12008-11-18 09:32:42 +01001227 struct auto_pin_cfg *cfg = &spec->autocfg;
1228 hda_nid_t nid;
Matt2f2f4252005-04-13 14:45:30 +02001229 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001230 int i;
Matt2f2f4252005-04-13 14:45:30 +02001231
1232 err = snd_hda_add_new_ctls(codec, spec->mixer);
1233 if (err < 0)
1234 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001235
1236 for (i = 0; i < spec->num_mixers; i++) {
1237 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1238 if (err < 0)
1239 return err;
1240 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001241 if (spec->num_dmuxes > 0) {
1242 stac_dmux_mixer.count = spec->num_dmuxes;
Takashi Iwaid13bd412008-07-30 15:01:45 +02001243 err = snd_hda_ctl_add(codec,
Takashi Iwai1697055e2007-12-18 18:05:52 +01001244 snd_ctl_new1(&stac_dmux_mixer, codec));
1245 if (err < 0)
1246 return err;
1247 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001248 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001249 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1250 struct hda_input_mux *smux = &spec->private_smux;
1251 /* check for mute support on SPDIF out */
1252 if (wcaps & AC_WCAP_OUT_AMP) {
1253 smux->items[smux->num_items].label = "Off";
1254 smux->items[smux->num_items].index = 0;
1255 smux->num_items++;
1256 spec->spdif_mute = 1;
1257 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001258 stac_smux_mixer.count = spec->num_smuxes;
Takashi Iwai4f2d23e2008-12-19 10:14:13 +01001259 err = snd_hda_ctl_add(codec,
Matthew Ranostayd9737752008-09-07 12:03:41 +02001260 snd_ctl_new1(&stac_smux_mixer, codec));
1261 if (err < 0)
1262 return err;
1263 }
Mattc7d4b2f2005-06-27 14:59:41 +02001264
Mattdabbed62005-06-14 10:19:34 +02001265 if (spec->multiout.dig_out_nid) {
1266 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1267 if (err < 0)
1268 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001269 err = snd_hda_create_spdif_share_sw(codec,
1270 &spec->multiout);
1271 if (err < 0)
1272 return err;
1273 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001274 }
Harvey Harrisonda74ae32008-10-21 20:28:04 -07001275 if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001276 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1277 if (err < 0)
1278 return err;
1279 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001280
1281 /* if we have no master control, let's create it */
1282 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001283 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001284 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001285 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001286 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001287 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001288 if (err < 0)
1289 return err;
1290 }
1291 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1292 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1293 NULL, slave_sws);
1294 if (err < 0)
1295 return err;
1296 }
1297
Takashi Iwai603c4012008-07-30 15:01:44 +02001298 stac92xx_free_kctls(codec); /* no longer needed */
Takashi Iwaie4973e12008-11-18 09:32:42 +01001299
1300 /* create jack input elements */
1301 if (spec->hp_detect) {
1302 for (i = 0; i < cfg->hp_outs; i++) {
1303 int type = SND_JACK_HEADPHONE;
1304 nid = cfg->hp_pins[i];
1305 /* jack detection */
1306 if (cfg->hp_outs == i)
1307 type |= SND_JACK_LINEOUT;
1308 err = stac92xx_add_jack(codec, nid, type);
1309 if (err < 0)
1310 return err;
1311 }
1312 }
1313 for (i = 0; i < cfg->line_outs; i++) {
1314 err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
1315 SND_JACK_LINEOUT);
1316 if (err < 0)
1317 return err;
1318 }
1319 for (i = 0; i < AUTO_PIN_LAST; i++) {
1320 nid = cfg->input_pins[i];
1321 if (nid) {
1322 err = stac92xx_add_jack(codec, nid,
1323 SND_JACK_MICROPHONE);
1324 if (err < 0)
1325 return err;
1326 }
1327 }
1328
Mattdabbed62005-06-14 10:19:34 +02001329 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001330}
1331
Matt Porter403d1942005-11-29 15:00:51 +01001332static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001333 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001334 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1335};
1336
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001337/*
1338 STAC 9200 pin configs for
1339 102801A8
1340 102801DE
1341 102801E8
1342*/
1343static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001344 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1345 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001346};
1347
1348/*
1349 STAC 9200 pin configs for
1350 102801C0
1351 102801C1
1352*/
1353static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001354 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1355 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001356};
1357
1358/*
1359 STAC 9200 pin configs for
1360 102801C4 (Dell Dimension E310)
1361 102801C5
1362 102801C7
1363 102801D9
1364 102801DA
1365 102801E3
1366*/
1367static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001368 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1369 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001370};
1371
1372
1373/*
1374 STAC 9200-32 pin configs for
1375 102801B5 (Dell Inspiron 630m)
1376 102801D8 (Dell Inspiron 640m)
1377*/
1378static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001379 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1380 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001381};
1382
1383/*
1384 STAC 9200-32 pin configs for
1385 102801C2 (Dell Latitude D620)
1386 102801C8
1387 102801CC (Dell Latitude D820)
1388 102801D4
1389 102801D6
1390*/
1391static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001392 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1393 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001394};
1395
1396/*
1397 STAC 9200-32 pin configs for
1398 102801CE (Dell XPS M1710)
1399 102801CF (Dell Precision M90)
1400*/
1401static unsigned int dell9200_m23_pin_configs[8] = {
1402 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1403 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1404};
1405
1406/*
1407 STAC 9200-32 pin configs for
1408 102801C9
1409 102801CA
1410 102801CB (Dell Latitude 120L)
1411 102801D3
1412*/
1413static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001414 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1415 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001416};
1417
1418/*
1419 STAC 9200-32 pin configs for
1420 102801BD (Dell Inspiron E1505n)
1421 102801EE
1422 102801EF
1423*/
1424static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001425 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1426 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001427};
1428
1429/*
1430 STAC 9200-32 pin configs for
1431 102801F5 (Dell Inspiron 1501)
1432 102801F6
1433*/
1434static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001435 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1436 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001437};
1438
1439/*
1440 STAC 9200-32
1441 102801CD (Dell Inspiron E1705/9400)
1442*/
1443static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001444 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1445 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001446};
1447
Tobin Davisbf277782008-02-03 20:31:47 +01001448static unsigned int oqo9200_pin_configs[8] = {
1449 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1450 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1451};
1452
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001453
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001454static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1455 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001456 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001457 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1458 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1459 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1460 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1461 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1462 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1463 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1464 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1465 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1466 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001467 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001468};
1469
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001470static const char *stac9200_models[STAC_9200_MODELS] = {
1471 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001472 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001473 [STAC_9200_DELL_D21] = "dell-d21",
1474 [STAC_9200_DELL_D22] = "dell-d22",
1475 [STAC_9200_DELL_D23] = "dell-d23",
1476 [STAC_9200_DELL_M21] = "dell-m21",
1477 [STAC_9200_DELL_M22] = "dell-m22",
1478 [STAC_9200_DELL_M23] = "dell-m23",
1479 [STAC_9200_DELL_M24] = "dell-m24",
1480 [STAC_9200_DELL_M25] = "dell-m25",
1481 [STAC_9200_DELL_M26] = "dell-m26",
1482 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001483 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001484 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001485};
1486
1487static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1488 /* SigmaTel reference board */
1489 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1490 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001491 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001492 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1493 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001494 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001495 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1496 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1497 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1498 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1499 "unknown Dell", STAC_9200_DELL_D22),
1500 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1501 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001502 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001503 "Dell Latitude D620", STAC_9200_DELL_M22),
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1505 "unknown Dell", STAC_9200_DELL_D23),
1506 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1507 "unknown Dell", STAC_9200_DELL_D23),
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1509 "unknown Dell", STAC_9200_DELL_M22),
1510 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1511 "unknown Dell", STAC_9200_DELL_M24),
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1513 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001514 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001515 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001516 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001517 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001518 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001519 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001520 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001521 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001522 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001523 "Dell Precision M90", STAC_9200_DELL_M23),
1524 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1525 "unknown Dell", STAC_9200_DELL_M22),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1527 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001528 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001529 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001530 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001531 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1533 "unknown Dell", STAC_9200_DELL_D23),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1535 "unknown Dell", STAC_9200_DELL_D23),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1537 "unknown Dell", STAC_9200_DELL_D21),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1539 "unknown Dell", STAC_9200_DELL_D23),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1541 "unknown Dell", STAC_9200_DELL_D21),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1543 "unknown Dell", STAC_9200_DELL_M25),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1545 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001546 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001547 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1549 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001550 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001551 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001552 /* Gateway machines needs EAPD to be set on resume */
1553 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1554 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1555 STAC_9200_GATEWAY),
1556 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1557 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001558 /* OQO Mobile */
1559 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001560 {} /* terminator */
1561};
1562
Tobin Davis8e21c342007-01-08 11:04:17 +01001563static unsigned int ref925x_pin_configs[8] = {
1564 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001565 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001566};
1567
1568static unsigned int stac925x_MA6_pin_configs[8] = {
1569 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1570 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1571};
1572
Tobin Davis2c11f952007-05-17 09:36:34 +02001573static unsigned int stac925x_PA6_pin_configs[8] = {
1574 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1575 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1576};
1577
Tobin Davis8e21c342007-01-08 11:04:17 +01001578static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001579 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1580 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001581};
1582
1583static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1584 [STAC_REF] = ref925x_pin_configs,
1585 [STAC_M2_2] = stac925xM2_2_pin_configs,
1586 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001587 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001588};
1589
1590static const char *stac925x_models[STAC_925x_MODELS] = {
1591 [STAC_REF] = "ref",
1592 [STAC_M2_2] = "m2-2",
1593 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001594 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001595};
1596
1597static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1598 /* SigmaTel reference board */
1599 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001600 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001601 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1602 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1603 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001604 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001605 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1606 {} /* terminator */
1607};
1608
Matthew Ranostaya7662642008-02-21 07:51:14 +01001609static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001610 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1611 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1612 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001613 0x01452050,
1614};
1615
1616static unsigned int dell_m6_pin_configs[13] = {
1617 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001618 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001619 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1620 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001621};
1622
1623static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001624 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001625 [STAC_DELL_M6_AMIC] = dell_m6_pin_configs,
1626 [STAC_DELL_M6_DMIC] = dell_m6_pin_configs,
1627 [STAC_DELL_M6_BOTH] = dell_m6_pin_configs,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001628 [STAC_DELL_EQ] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001629};
1630
1631static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
Takashi Iwai9e43f0d2008-12-17 14:51:01 +01001632 [STAC_92HD73XX_NO_JD] = "no-jd",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001633 [STAC_92HD73XX_REF] = "ref",
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001634 [STAC_DELL_M6_AMIC] = "dell-m6-amic",
1635 [STAC_DELL_M6_DMIC] = "dell-m6-dmic",
1636 [STAC_DELL_M6_BOTH] = "dell-m6",
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001637 [STAC_DELL_EQ] = "dell-eq",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001638};
1639
1640static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1641 /* SigmaTel reference board */
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001643 "DFI LanParty", STAC_92HD73XX_REF),
1644 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001645 "Dell Studio 1535", STAC_DELL_M6_DMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001647 "unknown Dell", STAC_DELL_M6_DMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001649 "unknown Dell", STAC_DELL_M6_BOTH),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001650 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001651 "unknown Dell", STAC_DELL_M6_BOTH),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001652 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001653 "unknown Dell", STAC_DELL_M6_AMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001654 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001655 "unknown Dell", STAC_DELL_M6_AMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001656 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001657 "unknown Dell", STAC_DELL_M6_DMIC),
1658 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272,
1659 "unknown Dell", STAC_DELL_M6_DMIC),
Takashi Iwaib0fc5e02008-11-21 08:37:03 +01001660 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001661 "Dell Studio 1537", STAC_DELL_M6_DMIC),
Joerg Schirottkefa620e92008-12-19 08:13:49 +01001662 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
1663 "Dell Studio 17", STAC_DELL_M6_DMIC),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001664 {} /* terminator */
1665};
1666
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001667static unsigned int ref92hd83xxx_pin_configs[14] = {
1668 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1669 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1670 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1671 0x01451160, 0x98560170,
1672};
1673
1674static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1675 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1676};
1677
1678static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1679 [STAC_92HD83XXX_REF] = "ref",
1680};
1681
1682static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1683 /* SigmaTel reference board */
1684 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1685 "DFI LanParty", STAC_92HD71BXX_REF),
Herton Ronaldo Krzesinski574f3c42008-12-23 16:53:00 -02001686 {} /* terminator */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001687};
1688
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001689static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001690 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001691 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001692 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001693};
1694
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001695static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001696 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001697 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001698 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001699};
1700
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001701static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001702 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1703 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001704 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001705};
1706
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001707static unsigned int dell_m4_3_pin_configs[11] = {
1708 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1709 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
1710 0x40f000f0, 0x044413b0, 0x044413b0,
1711};
1712
Matthew Ranostaye035b842007-11-06 11:53:55 +01001713static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1714 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001715 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1716 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001717 [STAC_DELL_M4_3] = dell_m4_3_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001718 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001719};
1720
1721static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1722 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001723 [STAC_DELL_M4_1] = "dell-m4-1",
1724 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001725 [STAC_DELL_M4_3] = "dell-m4-3",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001726 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001727};
1728
1729static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1730 /* SigmaTel reference board */
1731 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1732 "DFI LanParty", STAC_92HD71BXX_REF),
Takashi Iwai80bf2722008-11-18 10:48:41 +01001733 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
1734 "HP dv5", STAC_HP_M4),
1735 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
1736 "HP dv7", STAC_HP_M4),
Takashi Iwai69dfaef2008-12-20 16:57:50 +01001737 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
1738 "HP dv7", STAC_HP_M4),
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04001739 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
1740 "unknown HP", STAC_HP_M4),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001741 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1742 "unknown Dell", STAC_DELL_M4_1),
1743 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1744 "unknown Dell", STAC_DELL_M4_1),
1745 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1746 "unknown Dell", STAC_DELL_M4_1),
1747 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1748 "unknown Dell", STAC_DELL_M4_1),
1749 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1750 "unknown Dell", STAC_DELL_M4_1),
1751 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1752 "unknown Dell", STAC_DELL_M4_1),
1753 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1754 "unknown Dell", STAC_DELL_M4_1),
1755 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1756 "unknown Dell", STAC_DELL_M4_2),
1757 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1758 "unknown Dell", STAC_DELL_M4_2),
1759 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1760 "unknown Dell", STAC_DELL_M4_2),
1761 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1762 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05001763 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa,
1764 "unknown Dell", STAC_DELL_M4_3),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001765 {} /* terminator */
1766};
1767
Matt Porter403d1942005-11-29 15:00:51 +01001768static unsigned int ref922x_pin_configs[10] = {
1769 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1770 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001771 0x40000100, 0x40000100,
1772};
1773
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001774/*
1775 STAC 922X pin configs for
1776 102801A7
1777 102801AB
1778 102801A9
1779 102801D1
1780 102801D2
1781*/
1782static unsigned int dell_922x_d81_pin_configs[10] = {
1783 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1784 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1785 0x01813122, 0x400001f2,
1786};
1787
1788/*
1789 STAC 922X pin configs for
1790 102801AC
1791 102801D0
1792*/
1793static unsigned int dell_922x_d82_pin_configs[10] = {
1794 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1795 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1796 0x01813122, 0x400001f1,
1797};
1798
1799/*
1800 STAC 922X pin configs for
1801 102801BF
1802*/
1803static unsigned int dell_922x_m81_pin_configs[10] = {
1804 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1805 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1806 0x40C003f1, 0x405003f0,
1807};
1808
1809/*
1810 STAC 9221 A1 pin configs for
1811 102801D7 (Dell XPS M1210)
1812*/
1813static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001814 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1815 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001816 0x508003f3, 0x405003f4,
1817};
1818
Matt Porter403d1942005-11-29 15:00:51 +01001819static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001820 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001821 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1822 0x02a19120, 0x40000100,
1823};
1824
1825static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001826 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1827 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001828 0x02a19320, 0x40000100,
1829};
1830
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001831static unsigned int intel_mac_v1_pin_configs[10] = {
1832 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1833 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001834 0x400000fc, 0x400000fb,
1835};
1836
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001837static unsigned int intel_mac_v2_pin_configs[10] = {
1838 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1839 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001840 0x400000fc, 0x400000fb,
1841};
1842
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001843static unsigned int intel_mac_v3_pin_configs[10] = {
1844 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1845 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1846 0x400000fc, 0x400000fb,
1847};
1848
1849static unsigned int intel_mac_v4_pin_configs[10] = {
1850 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1851 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1852 0x400000fc, 0x400000fb,
1853};
1854
1855static unsigned int intel_mac_v5_pin_configs[10] = {
1856 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1857 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1858 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001859};
1860
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001861static unsigned int ecs202_pin_configs[10] = {
1862 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1863 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1864 0x9037012e, 0x40e000f2,
1865};
Takashi Iwai76c08822007-06-19 12:17:42 +02001866
Takashi Iwai19039bd2006-06-28 15:52:16 +02001867static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001868 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001869 [STAC_D945GTP3] = d945gtp3_pin_configs,
1870 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001871 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1872 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1873 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1874 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1875 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001876 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001877 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001878 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1879 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1880 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1881 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1882 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1883 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001884 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001885 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1886 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1887 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1888 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001889};
1890
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001891static const char *stac922x_models[STAC_922X_MODELS] = {
1892 [STAC_D945_REF] = "ref",
1893 [STAC_D945GTP5] = "5stack",
1894 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001895 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1896 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1897 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1898 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1899 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001900 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001901 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001902 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001903 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001904 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1905 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001906 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001907 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001908 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001909 [STAC_922X_DELL_D81] = "dell-d81",
1910 [STAC_922X_DELL_D82] = "dell-d82",
1911 [STAC_922X_DELL_M81] = "dell-m81",
1912 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001913};
1914
1915static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1916 /* SigmaTel reference board */
1917 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1918 "DFI LanParty", STAC_D945_REF),
1919 /* Intel 945G based systems */
1920 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1921 "Intel D945G", STAC_D945GTP3),
1922 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1923 "Intel D945G", STAC_D945GTP3),
1924 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1925 "Intel D945G", STAC_D945GTP3),
1926 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1927 "Intel D945G", STAC_D945GTP3),
1928 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1929 "Intel D945G", STAC_D945GTP3),
1930 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1931 "Intel D945G", STAC_D945GTP3),
1932 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1933 "Intel D945G", STAC_D945GTP3),
1934 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1935 "Intel D945G", STAC_D945GTP3),
1936 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1937 "Intel D945G", STAC_D945GTP3),
1938 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1939 "Intel D945G", STAC_D945GTP3),
1940 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1941 "Intel D945G", STAC_D945GTP3),
1942 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1943 "Intel D945G", STAC_D945GTP3),
1944 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1945 "Intel D945G", STAC_D945GTP3),
1946 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1947 "Intel D945G", STAC_D945GTP3),
1948 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1949 "Intel D945G", STAC_D945GTP3),
1950 /* Intel D945G 5-stack systems */
1951 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1952 "Intel D945G", STAC_D945GTP5),
1953 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1954 "Intel D945G", STAC_D945GTP5),
1955 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1956 "Intel D945G", STAC_D945GTP5),
1957 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1958 "Intel D945G", STAC_D945GTP5),
1959 /* Intel 945P based systems */
1960 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1961 "Intel D945P", STAC_D945GTP3),
1962 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1963 "Intel D945P", STAC_D945GTP3),
1964 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1965 "Intel D945P", STAC_D945GTP3),
1966 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1967 "Intel D945P", STAC_D945GTP3),
1968 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1969 "Intel D945P", STAC_D945GTP3),
1970 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1971 "Intel D945P", STAC_D945GTP5),
1972 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001973 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001974 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001975 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001976 /* Dell systems */
1977 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1978 "unknown Dell", STAC_922X_DELL_D81),
1979 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1980 "unknown Dell", STAC_922X_DELL_D81),
1981 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1982 "unknown Dell", STAC_922X_DELL_D81),
1983 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1984 "unknown Dell", STAC_922X_DELL_D82),
1985 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1986 "unknown Dell", STAC_922X_DELL_M81),
1987 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1988 "unknown Dell", STAC_922X_DELL_D82),
1989 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1990 "unknown Dell", STAC_922X_DELL_D81),
1991 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1992 "unknown Dell", STAC_922X_DELL_D81),
1993 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1994 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001995 /* ECS/PC Chips boards */
1996 SND_PCI_QUIRK(0x1019, 0x2144,
1997 "ECS/PC chips", STAC_ECS_202),
1998 SND_PCI_QUIRK(0x1019, 0x2608,
1999 "ECS/PC chips", STAC_ECS_202),
2000 SND_PCI_QUIRK(0x1019, 0x2633,
2001 "ECS/PC chips P17G/1333", STAC_ECS_202),
2002 SND_PCI_QUIRK(0x1019, 0x2811,
2003 "ECS/PC chips", STAC_ECS_202),
2004 SND_PCI_QUIRK(0x1019, 0x2812,
2005 "ECS/PC chips", STAC_ECS_202),
2006 SND_PCI_QUIRK(0x1019, 0x2813,
2007 "ECS/PC chips", STAC_ECS_202),
2008 SND_PCI_QUIRK(0x1019, 0x2814,
2009 "ECS/PC chips", STAC_ECS_202),
2010 SND_PCI_QUIRK(0x1019, 0x2815,
2011 "ECS/PC chips", STAC_ECS_202),
2012 SND_PCI_QUIRK(0x1019, 0x2816,
2013 "ECS/PC chips", STAC_ECS_202),
2014 SND_PCI_QUIRK(0x1019, 0x2817,
2015 "ECS/PC chips", STAC_ECS_202),
2016 SND_PCI_QUIRK(0x1019, 0x2818,
2017 "ECS/PC chips", STAC_ECS_202),
2018 SND_PCI_QUIRK(0x1019, 0x2819,
2019 "ECS/PC chips", STAC_ECS_202),
2020 SND_PCI_QUIRK(0x1019, 0x2820,
2021 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01002022 {} /* terminator */
2023};
2024
Matt Porter3cc08dc2006-01-23 15:27:49 +01002025static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02002026 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2027 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
2028 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
2029 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002030};
2031
Tobin Davis93ed1502006-09-01 21:03:12 +02002032static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002033 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
2034 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
2035 0x40000100, 0x40000100, 0x40000100, 0x40000100,
2036 0x40000100, 0x40000100
2037};
2038
Tobin Davis93ed1502006-09-01 21:03:12 +02002039static unsigned int d965_5st_pin_configs[14] = {
2040 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2041 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
2042 0x40000100, 0x40000100, 0x40000100, 0x01442070,
2043 0x40000100, 0x40000100
2044};
2045
Tobin Davis4ff076e2007-08-07 11:48:12 +02002046static unsigned int dell_3st_pin_configs[14] = {
2047 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
2048 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002049 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02002050 0x40c003fc, 0x40000100
2051};
2052
Tobin Davis93ed1502006-09-01 21:03:12 +02002053static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Takashi Iwaie28d8322008-12-17 13:48:29 +01002054 [STAC_D965_REF_NO_JD] = ref927x_pin_configs,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002055 [STAC_D965_REF] = ref927x_pin_configs,
2056 [STAC_D965_3ST] = d965_3st_pin_configs,
2057 [STAC_D965_5ST] = d965_5st_pin_configs,
2058 [STAC_DELL_3ST] = dell_3st_pin_configs,
2059 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002060};
2061
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002062static const char *stac927x_models[STAC_927X_MODELS] = {
Takashi Iwaie28d8322008-12-17 13:48:29 +01002063 [STAC_D965_REF_NO_JD] = "ref-no-jd",
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002064 [STAC_D965_REF] = "ref",
2065 [STAC_D965_3ST] = "3stack",
2066 [STAC_D965_5ST] = "5stack",
2067 [STAC_DELL_3ST] = "dell-3stack",
2068 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002069};
2070
2071static struct snd_pci_quirk stac927x_cfg_tbl[] = {
2072 /* SigmaTel reference board */
2073 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2074 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002075 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002076 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2077 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002078 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002079 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
2080 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
2081 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
2082 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
2083 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
2084 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
2085 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
2086 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
2087 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
2088 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
2089 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
2090 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
2091 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
2092 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
2093 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
2094 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002095 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002096 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002097 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002098 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2099 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002100 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002101 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
2102 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002103 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02002104 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002105 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2106 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2107 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2108 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002109 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002110 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
2111 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
2112 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
2113 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
2114 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
2115 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
2116 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
2117 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
2118 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002119 {} /* terminator */
2120};
2121
Matt Porterf3302a52006-07-31 12:49:34 +02002122static unsigned int ref9205_pin_configs[12] = {
2123 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002124 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02002125 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02002126};
2127
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002128/*
2129 STAC 9205 pin configs for
2130 102801F1
2131 102801F2
2132 102801FC
2133 102801FD
2134 10280204
2135 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002136 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002137*/
2138static unsigned int dell_9205_m42_pin_configs[12] = {
2139 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
2140 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
2141 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
2142};
2143
2144/*
2145 STAC 9205 pin configs for
2146 102801F9
2147 102801FA
2148 102801FE
2149 102801FF (Dell Precision M4300)
2150 10280206
2151 10280200
2152 10280201
2153*/
2154static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002155 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
2156 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
2157 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
2158};
2159
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002160static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002161 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
2162 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
2163 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
2164};
2165
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002166static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002167 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002168 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
2169 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
2170 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02002171};
2172
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002173static const char *stac9205_models[STAC_9205_MODELS] = {
2174 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002175 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002176 [STAC_9205_DELL_M43] = "dell-m43",
2177 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002178};
2179
2180static struct snd_pci_quirk stac9205_cfg_tbl[] = {
2181 /* SigmaTel reference board */
2182 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2183 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002184 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2185 "unknown Dell", STAC_9205_DELL_M42),
2186 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2187 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002188 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002189 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002190 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2191 "Dell Precision", STAC_9205_DELL_M43),
2192 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2193 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002194 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2195 "unknown Dell", STAC_9205_DELL_M42),
2196 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2197 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002198 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2199 "Dell Precision", STAC_9205_DELL_M43),
2200 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002201 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002202 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2203 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002204 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2205 "Dell Precision", STAC_9205_DELL_M43),
2206 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2207 "Dell Precision", STAC_9205_DELL_M43),
2208 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2209 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002210 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2211 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002212 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2213 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002214 {} /* terminator */
2215};
2216
Richard Fish11b44bb2006-08-23 18:31:34 +02002217static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2218{
2219 int i;
2220 struct sigmatel_spec *spec = codec->spec;
2221
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002222 kfree(spec->pin_configs);
2223 spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs),
2224 GFP_KERNEL);
2225 if (!spec->pin_configs)
2226 return -ENOMEM;
Richard Fish11b44bb2006-08-23 18:31:34 +02002227
2228 for (i = 0; i < spec->num_pins; i++) {
2229 hda_nid_t nid = spec->pin_nids[i];
2230 unsigned int pin_cfg;
2231
2232 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2233 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2234 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2235 nid, pin_cfg);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002236 spec->pin_configs[i] = pin_cfg;
Richard Fish11b44bb2006-08-23 18:31:34 +02002237 }
2238
2239 return 0;
2240}
2241
Matthew Ranostay87d48362007-07-17 11:52:24 +02002242static void stac92xx_set_config_reg(struct hda_codec *codec,
2243 hda_nid_t pin_nid, unsigned int pin_config)
2244{
2245 int i;
2246 snd_hda_codec_write(codec, pin_nid, 0,
2247 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2248 pin_config & 0x000000ff);
2249 snd_hda_codec_write(codec, pin_nid, 0,
2250 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2251 (pin_config & 0x0000ff00) >> 8);
2252 snd_hda_codec_write(codec, pin_nid, 0,
2253 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2254 (pin_config & 0x00ff0000) >> 16);
2255 snd_hda_codec_write(codec, pin_nid, 0,
2256 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2257 pin_config >> 24);
2258 i = snd_hda_codec_read(codec, pin_nid, 0,
2259 AC_VERB_GET_CONFIG_DEFAULT,
2260 0x00);
2261 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2262 pin_nid, i);
2263}
2264
Matt2f2f4252005-04-13 14:45:30 +02002265static void stac92xx_set_config_regs(struct hda_codec *codec)
2266{
2267 int i;
2268 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002269
Matthew Ranostay87d48362007-07-17 11:52:24 +02002270 if (!spec->pin_configs)
2271 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002272
Matthew Ranostay87d48362007-07-17 11:52:24 +02002273 for (i = 0; i < spec->num_pins; i++)
2274 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2275 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002276}
Matt2f2f4252005-04-13 14:45:30 +02002277
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002278static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins)
2279{
2280 struct sigmatel_spec *spec = codec->spec;
2281
2282 if (!pins)
2283 return stac92xx_save_bios_config_regs(codec);
2284
2285 kfree(spec->pin_configs);
2286 spec->pin_configs = kmemdup(pins,
2287 spec->num_pins * sizeof(*pins),
2288 GFP_KERNEL);
2289 if (!spec->pin_configs)
2290 return -ENOMEM;
2291
2292 stac92xx_set_config_regs(codec);
2293 return 0;
2294}
2295
2296static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid,
2297 unsigned int cfg)
2298{
2299 struct sigmatel_spec *spec = codec->spec;
2300 int i;
2301
2302 for (i = 0; i < spec->num_pins; i++) {
2303 if (spec->pin_nids[i] == nid) {
2304 spec->pin_configs[i] = cfg;
2305 stac92xx_set_config_reg(codec, nid, cfg);
2306 break;
2307 }
2308 }
2309}
2310
Matt2f2f4252005-04-13 14:45:30 +02002311/*
2312 * Analog playback callbacks
2313 */
2314static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2315 struct hda_codec *codec,
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 if (spec->stream_delay)
2320 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002321 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2322 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002323}
2324
2325static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2326 struct hda_codec *codec,
2327 unsigned int stream_tag,
2328 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002329 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002330{
2331 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002332 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002333}
2334
2335static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2336 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002337 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002338{
2339 struct sigmatel_spec *spec = codec->spec;
2340 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2341}
2342
2343/*
Mattdabbed62005-06-14 10:19:34 +02002344 * Digital playback callbacks
2345 */
2346static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2347 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002348 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002349{
2350 struct sigmatel_spec *spec = codec->spec;
2351 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2352}
2353
2354static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2355 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002356 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002357{
2358 struct sigmatel_spec *spec = codec->spec;
2359 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2360}
2361
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002362static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2363 struct hda_codec *codec,
2364 unsigned int stream_tag,
2365 unsigned int format,
2366 struct snd_pcm_substream *substream)
2367{
2368 struct sigmatel_spec *spec = codec->spec;
2369 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2370 stream_tag, format, substream);
2371}
2372
Mattdabbed62005-06-14 10:19:34 +02002373
2374/*
Matt2f2f4252005-04-13 14:45:30 +02002375 * Analog capture callbacks
2376 */
2377static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2378 struct hda_codec *codec,
2379 unsigned int stream_tag,
2380 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002381 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002382{
2383 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002384 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002385
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002386 if (spec->powerdown_adcs) {
2387 msleep(40);
Takashi Iwai8c2f7672008-12-01 11:54:35 +01002388 snd_hda_codec_write(codec, nid, 0,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002389 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2390 }
2391 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002392 return 0;
2393}
2394
2395static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2396 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002397 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002398{
2399 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002400 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002401
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002402 snd_hda_codec_cleanup_stream(codec, nid);
2403 if (spec->powerdown_adcs)
Takashi Iwai8c2f7672008-12-01 11:54:35 +01002404 snd_hda_codec_write(codec, nid, 0,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002405 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002406 return 0;
2407}
2408
Mattdabbed62005-06-14 10:19:34 +02002409static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2410 .substreams = 1,
2411 .channels_min = 2,
2412 .channels_max = 2,
2413 /* NID is set in stac92xx_build_pcms */
2414 .ops = {
2415 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002416 .close = stac92xx_dig_playback_pcm_close,
2417 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002418 },
2419};
2420
2421static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2422 .substreams = 1,
2423 .channels_min = 2,
2424 .channels_max = 2,
2425 /* NID is set in stac92xx_build_pcms */
2426};
2427
Matt2f2f4252005-04-13 14:45:30 +02002428static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2429 .substreams = 1,
2430 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002431 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002432 .nid = 0x02, /* NID to query formats and rates */
2433 .ops = {
2434 .open = stac92xx_playback_pcm_open,
2435 .prepare = stac92xx_playback_pcm_prepare,
2436 .cleanup = stac92xx_playback_pcm_cleanup
2437 },
2438};
2439
Matt Porter3cc08dc2006-01-23 15:27:49 +01002440static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2441 .substreams = 1,
2442 .channels_min = 2,
2443 .channels_max = 2,
2444 .nid = 0x06, /* NID to query formats and rates */
2445 .ops = {
2446 .open = stac92xx_playback_pcm_open,
2447 .prepare = stac92xx_playback_pcm_prepare,
2448 .cleanup = stac92xx_playback_pcm_cleanup
2449 },
2450};
2451
Matt2f2f4252005-04-13 14:45:30 +02002452static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002453 .channels_min = 2,
2454 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002455 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002456 .ops = {
2457 .prepare = stac92xx_capture_pcm_prepare,
2458 .cleanup = stac92xx_capture_pcm_cleanup
2459 },
2460};
2461
2462static int stac92xx_build_pcms(struct hda_codec *codec)
2463{
2464 struct sigmatel_spec *spec = codec->spec;
2465 struct hda_pcm *info = spec->pcm_rec;
2466
2467 codec->num_pcms = 1;
2468 codec->pcm_info = info;
2469
Mattc7d4b2f2005-06-27 14:59:41 +02002470 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002471 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002472 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002473 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002474 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002475
2476 if (spec->alt_switch) {
2477 codec->num_pcms++;
2478 info++;
2479 info->name = "STAC92xx Analog Alt";
2480 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2481 }
Matt2f2f4252005-04-13 14:45:30 +02002482
Mattdabbed62005-06-14 10:19:34 +02002483 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2484 codec->num_pcms++;
2485 info++;
2486 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002487 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002488 if (spec->multiout.dig_out_nid) {
2489 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2490 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2491 }
2492 if (spec->dig_in_nid) {
2493 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2494 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2495 }
2496 }
2497
Matt2f2f4252005-04-13 14:45:30 +02002498 return 0;
2499}
2500
Takashi Iwaic960a032006-03-23 17:06:28 +01002501static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2502{
2503 unsigned int pincap = snd_hda_param_read(codec, nid,
2504 AC_PAR_PIN_CAP);
2505 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2506 if (pincap & AC_PINCAP_VREF_100)
2507 return AC_PINCTL_VREF_100;
2508 if (pincap & AC_PINCAP_VREF_80)
2509 return AC_PINCTL_VREF_80;
2510 if (pincap & AC_PINCAP_VREF_50)
2511 return AC_PINCTL_VREF_50;
2512 if (pincap & AC_PINCAP_VREF_GRD)
2513 return AC_PINCTL_VREF_GRD;
2514 return 0;
2515}
2516
Matt Porter403d1942005-11-29 15:00:51 +01002517static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2518
2519{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002520 snd_hda_codec_write_cache(codec, nid, 0,
2521 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002522}
2523
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002524#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2525
2526static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2527 struct snd_ctl_elem_value *ucontrol)
2528{
2529 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2530 struct sigmatel_spec *spec = codec->spec;
2531
Takashi Iwaid7a89432008-11-12 09:48:04 +01002532 ucontrol->value.integer.value[0] = !!spec->hp_switch;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002533 return 0;
2534}
2535
Takashi Iwaic6e4c662008-11-25 11:58:19 +01002536static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
2537 unsigned char type);
2538
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002539static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2540 struct snd_ctl_elem_value *ucontrol)
2541{
2542 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2543 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaid7a89432008-11-12 09:48:04 +01002544 int nid = kcontrol->private_value;
2545
2546 spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002547
2548 /* check to be sure that the ports are upto date with
2549 * switch changes
2550 */
Takashi Iwaic6e4c662008-11-25 11:58:19 +01002551 stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002552
2553 return 1;
2554}
2555
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002556#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002557
2558static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2559{
2560 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2561 struct sigmatel_spec *spec = codec->spec;
2562 int io_idx = kcontrol-> private_value & 0xff;
2563
2564 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2565 return 0;
2566}
2567
2568static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2569{
2570 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2571 struct sigmatel_spec *spec = codec->spec;
2572 hda_nid_t nid = kcontrol->private_value >> 8;
2573 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002574 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002575
2576 spec->io_switch[io_idx] = val;
2577
2578 if (val)
2579 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002580 else {
2581 unsigned int pinctl = AC_PINCTL_IN_EN;
2582 if (io_idx) /* set VREF for mic */
2583 pinctl |= stac92xx_get_vref(codec, nid);
2584 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2585 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002586
2587 /* check the auto-mute again: we need to mute/unmute the speaker
2588 * appropriately according to the pin direction
2589 */
2590 if (spec->hp_detect)
Takashi Iwaic6e4c662008-11-25 11:58:19 +01002591 stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
Jiang Zhe40c1d302007-11-12 13:05:16 +01002592
Matt Porter403d1942005-11-29 15:00:51 +01002593 return 1;
2594}
2595
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002596#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2597
2598static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2599 struct snd_ctl_elem_value *ucontrol)
2600{
2601 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2602 struct sigmatel_spec *spec = codec->spec;
2603
2604 ucontrol->value.integer.value[0] = spec->clfe_swap;
2605 return 0;
2606}
2607
2608static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2609 struct snd_ctl_elem_value *ucontrol)
2610{
2611 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2612 struct sigmatel_spec *spec = codec->spec;
2613 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002614 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002615
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002616 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002617 return 0;
2618
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002619 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002620
2621 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2622 spec->clfe_swap ? 0x4 : 0x0);
2623
2624 return 1;
2625}
2626
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002627#define STAC_CODEC_HP_SWITCH(xname) \
2628 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2629 .name = xname, \
2630 .index = 0, \
2631 .info = stac92xx_hp_switch_info, \
2632 .get = stac92xx_hp_switch_get, \
2633 .put = stac92xx_hp_switch_put, \
2634 }
2635
Matt Porter403d1942005-11-29 15:00:51 +01002636#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2637 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2638 .name = xname, \
2639 .index = 0, \
2640 .info = stac92xx_io_switch_info, \
2641 .get = stac92xx_io_switch_get, \
2642 .put = stac92xx_io_switch_put, \
2643 .private_value = xpval, \
2644 }
2645
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002646#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2647 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2648 .name = xname, \
2649 .index = 0, \
2650 .info = stac92xx_clfe_switch_info, \
2651 .get = stac92xx_clfe_switch_get, \
2652 .put = stac92xx_clfe_switch_put, \
2653 .private_value = xpval, \
2654 }
Matt Porter403d1942005-11-29 15:00:51 +01002655
Mattc7d4b2f2005-06-27 14:59:41 +02002656enum {
2657 STAC_CTL_WIDGET_VOL,
2658 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002659 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002660 STAC_CTL_WIDGET_AMP_MUX,
2661 STAC_CTL_WIDGET_AMP_VOL,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002662 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002663 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002664 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002665};
2666
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002667static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002668 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2669 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002670 STAC_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002671 STAC_AMP_MUX,
2672 STAC_AMP_VOL(NULL, 0, 0, 0, 0),
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002673 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002674 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002675 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002676};
2677
2678/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002679static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
2680 struct snd_kcontrol_new *ktemp,
2681 int idx, const char *name,
2682 unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002683{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002684 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002685
Takashi Iwai603c4012008-07-30 15:01:44 +02002686 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2687 knew = snd_array_new(&spec->kctls);
2688 if (!knew)
2689 return -ENOMEM;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002690 *knew = *ktemp;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002691 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002692 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002693 if (!knew->name)
Mattc7d4b2f2005-06-27 14:59:41 +02002694 return -ENOMEM;
2695 knew->private_value = val;
Mattc7d4b2f2005-06-27 14:59:41 +02002696 return 0;
2697}
2698
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002699static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
2700 int type, int idx, const char *name,
2701 unsigned long val)
2702{
2703 return stac92xx_add_control_temp(spec,
2704 &stac92xx_control_templates[type],
2705 idx, name, val);
2706}
2707
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002708
2709/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002710static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2711 const char *name, unsigned long val)
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002712{
2713 return stac92xx_add_control_idx(spec, type, 0, name, val);
2714}
2715
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002716/* check whether the line-input can be used as line-out */
2717static hda_nid_t check_line_out_switch(struct hda_codec *codec)
Matt Porter403d1942005-11-29 15:00:51 +01002718{
2719 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002720 struct auto_pin_cfg *cfg = &spec->autocfg;
2721 hda_nid_t nid;
2722 unsigned int pincap;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002723
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002724 if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
2725 return 0;
2726 nid = cfg->input_pins[AUTO_PIN_LINE];
2727 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
2728 if (pincap & AC_PINCAP_OUT)
2729 return nid;
Matt Porter403d1942005-11-29 15:00:51 +01002730 return 0;
2731}
2732
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002733/* check whether the mic-input can be used as line-out */
2734static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
2735{
2736 struct sigmatel_spec *spec = codec->spec;
2737 struct auto_pin_cfg *cfg = &spec->autocfg;
2738 unsigned int def_conf, pincap;
2739 unsigned int mic_pin;
2740
2741 if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
2742 return 0;
2743 mic_pin = AUTO_PIN_MIC;
2744 for (;;) {
2745 hda_nid_t nid = cfg->input_pins[mic_pin];
2746 def_conf = snd_hda_codec_read(codec, nid, 0,
2747 AC_VERB_GET_CONFIG_DEFAULT, 0);
2748 /* some laptops have an internal analog microphone
2749 * which can't be used as a output */
2750 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2751 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
2752 if (pincap & AC_PINCAP_OUT)
2753 return nid;
2754 }
2755 if (mic_pin == AUTO_PIN_MIC)
2756 mic_pin = AUTO_PIN_FRONT_MIC;
2757 else
2758 break;
2759 }
2760 return 0;
2761}
Steve Longerbeam7b043892007-05-03 20:50:03 +02002762
2763static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2764{
2765 int i;
2766
2767 for (i = 0; i < spec->multiout.num_dacs; i++) {
2768 if (spec->multiout.dac_nids[i] == nid)
2769 return 1;
2770 }
2771
2772 return 0;
2773}
2774
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002775static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2776{
2777 int i;
2778 if (is_in_dac_nids(spec, nid))
2779 return 1;
2780 for (i = 0; i < spec->autocfg.hp_outs; i++)
2781 if (spec->hp_dacs[i] == nid)
2782 return 1;
2783 for (i = 0; i < spec->autocfg.speaker_outs; i++)
2784 if (spec->speaker_dacs[i] == nid)
2785 return 1;
2786 return 0;
2787}
2788
2789static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
2790{
2791 struct sigmatel_spec *spec = codec->spec;
2792 int j, conn_len;
2793 hda_nid_t conn[HDA_MAX_CONNECTIONS];
2794 unsigned int wcaps, wtype;
2795
2796 conn_len = snd_hda_get_connections(codec, nid, conn,
2797 HDA_MAX_CONNECTIONS);
2798 for (j = 0; j < conn_len; j++) {
2799 wcaps = snd_hda_param_read(codec, conn[j],
2800 AC_PAR_AUDIO_WIDGET_CAP);
2801 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
2802 /* we check only analog outputs */
2803 if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
2804 continue;
2805 /* if this route has a free DAC, assign it */
2806 if (!check_all_dac_nids(spec, conn[j])) {
2807 if (conn_len > 1) {
2808 /* select this DAC in the pin's input mux */
2809 snd_hda_codec_write_cache(codec, nid, 0,
2810 AC_VERB_SET_CONNECT_SEL, j);
2811 }
2812 return conn[j];
2813 }
2814 }
2815 return 0;
2816}
2817
2818static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
2819static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
2820
Matt Porter3cc08dc2006-01-23 15:27:49 +01002821/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002822 * Fill in the dac_nids table from the parsed pin configuration
2823 * This function only works when every pin in line_out_pins[]
2824 * contains atleast one DAC in its connection list. Some 92xx
2825 * codecs are not connected directly to a DAC, such as the 9200
2826 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002827 */
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002828static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
Mattc7d4b2f2005-06-27 14:59:41 +02002829{
2830 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002831 struct auto_pin_cfg *cfg = &spec->autocfg;
2832 int i;
2833 hda_nid_t nid, dac;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002834
Mattc7d4b2f2005-06-27 14:59:41 +02002835 for (i = 0; i < cfg->line_outs; i++) {
2836 nid = cfg->line_out_pins[i];
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002837 dac = get_unassigned_dac(codec, nid);
2838 if (!dac) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002839 if (spec->multiout.num_dacs > 0) {
2840 /* we have already working output pins,
2841 * so let's drop the broken ones again
2842 */
2843 cfg->line_outs = spec->multiout.num_dacs;
2844 break;
2845 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002846 /* error out, no available DAC found */
2847 snd_printk(KERN_ERR
2848 "%s: No available DAC for pin 0x%x\n",
2849 __func__, nid);
2850 return -ENODEV;
2851 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002852 add_spec_dacs(spec, dac);
2853 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002854
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002855 /* add line-in as output */
2856 nid = check_line_out_switch(codec);
2857 if (nid) {
2858 dac = get_unassigned_dac(codec, nid);
2859 if (dac) {
2860 snd_printdd("STAC: Add line-in 0x%x as output %d\n",
2861 nid, cfg->line_outs);
2862 cfg->line_out_pins[cfg->line_outs] = nid;
2863 cfg->line_outs++;
2864 spec->line_switch = nid;
2865 add_spec_dacs(spec, dac);
2866 }
2867 }
2868 /* add mic as output */
2869 nid = check_mic_out_switch(codec);
2870 if (nid) {
2871 dac = get_unassigned_dac(codec, nid);
2872 if (dac) {
2873 snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
2874 nid, cfg->line_outs);
2875 cfg->line_out_pins[cfg->line_outs] = nid;
2876 cfg->line_outs++;
2877 spec->mic_switch = nid;
2878 add_spec_dacs(spec, dac);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002879 }
Mattc7d4b2f2005-06-27 14:59:41 +02002880 }
2881
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002882 for (i = 0; i < cfg->hp_outs; i++) {
2883 nid = cfg->hp_pins[i];
2884 dac = get_unassigned_dac(codec, nid);
2885 if (dac) {
2886 if (!spec->multiout.hp_nid)
2887 spec->multiout.hp_nid = dac;
2888 else
2889 add_spec_extra_dacs(spec, dac);
2890 }
2891 spec->hp_dacs[i] = dac;
2892 }
2893
2894 for (i = 0; i < cfg->speaker_outs; i++) {
2895 nid = cfg->speaker_pins[i];
2896 dac = get_unassigned_dac(codec, nid);
2897 if (dac)
2898 add_spec_extra_dacs(spec, dac);
2899 spec->speaker_dacs[i] = dac;
2900 }
2901
2902 snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
Steve Longerbeam7b043892007-05-03 20:50:03 +02002903 spec->multiout.num_dacs,
2904 spec->multiout.dac_nids[0],
2905 spec->multiout.dac_nids[1],
2906 spec->multiout.dac_nids[2],
2907 spec->multiout.dac_nids[3],
2908 spec->multiout.dac_nids[4]);
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002909
Mattc7d4b2f2005-06-27 14:59:41 +02002910 return 0;
2911}
2912
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002913/* create volume control/switch for the given prefx type */
2914static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2915{
2916 char name[32];
2917 int err;
2918
2919 sprintf(name, "%s Playback Volume", pfx);
2920 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2921 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2922 if (err < 0)
2923 return err;
2924 sprintf(name, "%s Playback Switch", pfx);
2925 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2926 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2927 if (err < 0)
2928 return err;
2929 return 0;
2930}
2931
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002932static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2933{
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002934 if (spec->multiout.num_dacs > 4) {
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002935 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2936 return 1;
2937 } else {
2938 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2939 spec->multiout.num_dacs++;
2940 }
2941 return 0;
2942}
2943
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002944static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002945{
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002946 int i;
2947 for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
2948 if (!spec->multiout.extra_out_nid[i]) {
2949 spec->multiout.extra_out_nid[i] = nid;
2950 return 0;
2951 }
2952 }
2953 printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
2954 return 1;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002955}
2956
Takashi Iwai76624532008-12-19 10:09:47 +01002957static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid)
2958{
2959 int i;
2960
2961 if (spec->autocfg.line_outs != 1)
2962 return 0;
2963 if (spec->multiout.hp_nid == nid)
2964 return 0;
2965 for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
2966 if (spec->multiout.extra_out_nid[i] == nid)
2967 return 0;
2968 return 1;
2969}
2970
Mattc7d4b2f2005-06-27 14:59:41 +02002971/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002972static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002973 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002974{
Takashi Iwai76624532008-12-19 10:09:47 +01002975 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002976 static const char *chname[4] = {
2977 "Front", "Surround", NULL /*CLFE*/, "Side"
2978 };
Matthew Ranostayd21995e2008-10-13 13:22:45 -04002979 hda_nid_t nid = 0;
Takashi Iwai91589232008-12-19 15:59:40 +01002980 int i, err;
2981 unsigned int wid_caps;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002982
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01002983 for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) {
Mattc7d4b2f2005-06-27 14:59:41 +02002984 nid = spec->multiout.dac_nids[i];
Mattc7d4b2f2005-06-27 14:59:41 +02002985 if (i == 2) {
2986 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002987 err = create_controls(spec, "Center", nid, 1);
2988 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002989 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002990 err = create_controls(spec, "LFE", nid, 2);
2991 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002992 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002993
2994 wid_caps = get_wcaps(codec, nid);
2995
2996 if (wid_caps & AC_WCAP_LR_SWAP) {
2997 err = stac92xx_add_control(spec,
2998 STAC_CTL_WIDGET_CLFE_SWITCH,
2999 "Swap Center/LFE Playback Switch", nid);
3000
3001 if (err < 0)
3002 return err;
3003 }
3004
Mattc7d4b2f2005-06-27 14:59:41 +02003005 } else {
Takashi Iwai76624532008-12-19 10:09:47 +01003006 const char *name = chname[i];
3007 /* if it's a single DAC, assign a better name */
3008 if (!i && is_unique_dac(spec, nid)) {
3009 switch (cfg->line_out_type) {
3010 case AUTO_PIN_HP_OUT:
3011 name = "Headphone";
3012 break;
3013 case AUTO_PIN_SPEAKER_OUT:
3014 name = "Speaker";
3015 break;
3016 }
3017 }
3018 err = create_controls(spec, name, nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003019 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003020 return err;
3021 }
3022 }
3023
Takashi Iwaia9cb5c92008-11-24 07:51:11 +01003024 if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003025 err = stac92xx_add_control(spec,
3026 STAC_CTL_WIDGET_HP_SWITCH,
Takashi Iwaid7a89432008-11-12 09:48:04 +01003027 "Headphone as Line Out Switch",
3028 cfg->hp_pins[cfg->hp_outs - 1]);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003029 if (err < 0)
3030 return err;
3031 }
3032
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01003033 if (spec->line_switch) {
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003034 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
3035 "Line In as Output Switch",
3036 spec->line_switch << 8);
3037 if (err < 0)
3038 return err;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01003039 }
Matt Porter403d1942005-11-29 15:00:51 +01003040
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01003041 if (spec->mic_switch) {
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003042 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH,
3043 "Mic as Output Switch",
3044 (spec->mic_switch << 8) | 1);
3045 if (err < 0)
3046 return err;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01003047 }
Matt Porter403d1942005-11-29 15:00:51 +01003048
Mattc7d4b2f2005-06-27 14:59:41 +02003049 return 0;
3050}
3051
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003052/* add playback controls for Speaker and HP outputs */
3053static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
3054 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02003055{
3056 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003057 hda_nid_t nid;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003058 int i, err, nums;
Mattc7d4b2f2005-06-27 14:59:41 +02003059
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003060 nums = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003061 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003062 static const char *pfxs[] = {
3063 "Headphone", "Headphone2", "Headphone3",
3064 };
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003065 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
3066 if (wid_caps & AC_WCAP_UNSOL_CAP)
3067 spec->hp_detect = 1;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003068 if (nums >= ARRAY_SIZE(pfxs))
Mattc7d4b2f2005-06-27 14:59:41 +02003069 continue;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003070 nid = spec->hp_dacs[i];
3071 if (!nid)
3072 continue;
3073 err = create_controls(spec, pfxs[nums++], nid, 3);
3074 if (err < 0)
3075 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003076 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003077 nums = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003078 for (i = 0; i < cfg->speaker_outs; i++) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003079 static const char *pfxs[] = {
3080 "Speaker", "External Speaker", "Speaker2",
3081 };
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003082 if (nums >= ARRAY_SIZE(pfxs))
3083 continue;
3084 nid = spec->speaker_dacs[i];
3085 if (!nid)
3086 continue;
3087 err = create_controls(spec, pfxs[nums++], nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003088 if (err < 0)
3089 return err;
3090 }
Mattc7d4b2f2005-06-27 14:59:41 +02003091 return 0;
3092}
3093
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003094/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003095static const char *stac92xx_mono_labels[4] = {
3096 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003097};
3098
3099/* create mono mux for mono out on capable codecs */
3100static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
3101{
3102 struct sigmatel_spec *spec = codec->spec;
3103 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
3104 int i, num_cons;
3105 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
3106
3107 num_cons = snd_hda_get_connections(codec,
3108 spec->mono_nid,
3109 con_lst,
3110 HDA_MAX_NUM_INPUTS);
3111 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
3112 return -EINVAL;
3113
3114 for (i = 0; i < num_cons; i++) {
3115 mono_mux->items[mono_mux->num_items].label =
3116 stac92xx_mono_labels[i];
3117 mono_mux->items[mono_mux->num_items].index = i;
3118 mono_mux->num_items++;
3119 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003120
3121 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
3122 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003123}
3124
Matthew Ranostay89385032008-09-11 09:49:39 -04003125/* labels for amp mux outputs */
3126static const char *stac92xx_amp_labels[3] = {
Matthew Ranostay4b33c762008-10-10 09:07:23 -04003127 "Front Microphone", "Microphone", "Line In",
Matthew Ranostay89385032008-09-11 09:49:39 -04003128};
3129
3130/* create amp out controls mux on capable codecs */
3131static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
3132{
3133 struct sigmatel_spec *spec = codec->spec;
3134 struct hda_input_mux *amp_mux = &spec->private_amp_mux;
3135 int i, err;
3136
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003137 for (i = 0; i < spec->num_amps; i++) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003138 amp_mux->items[amp_mux->num_items].label =
3139 stac92xx_amp_labels[i];
3140 amp_mux->items[amp_mux->num_items].index = i;
3141 amp_mux->num_items++;
3142 }
3143
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003144 if (spec->num_amps > 1) {
3145 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
3146 "Amp Selector Capture Switch", 0);
3147 if (err < 0)
3148 return err;
3149 }
Matthew Ranostay89385032008-09-11 09:49:39 -04003150 return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
3151 "Amp Capture Volume",
3152 HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
3153}
3154
3155
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003156/* create PC beep volume controls */
3157static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3158 hda_nid_t nid)
3159{
3160 struct sigmatel_spec *spec = codec->spec;
3161 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3162 int err;
3163
3164 /* check for mute support for the the amp */
3165 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3166 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3167 "PC Beep Playback Switch",
3168 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3169 if (err < 0)
3170 return err;
3171 }
3172
3173 /* check to see if there is volume support for the amp */
3174 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3175 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
3176 "PC Beep Playback Volume",
3177 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3178 if (err < 0)
3179 return err;
3180 }
3181 return 0;
3182}
3183
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003184#ifdef CONFIG_SND_HDA_INPUT_BEEP
3185#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
3186
3187static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
3188 struct snd_ctl_elem_value *ucontrol)
3189{
3190 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3191 ucontrol->value.integer.value[0] = codec->beep->enabled;
3192 return 0;
3193}
3194
3195static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
3196 struct snd_ctl_elem_value *ucontrol)
3197{
3198 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3199 int enabled = !!ucontrol->value.integer.value[0];
3200 if (codec->beep->enabled != enabled) {
3201 codec->beep->enabled = enabled;
3202 return 1;
3203 }
3204 return 0;
3205}
3206
3207static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
3208 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3209 .info = stac92xx_dig_beep_switch_info,
3210 .get = stac92xx_dig_beep_switch_get,
3211 .put = stac92xx_dig_beep_switch_put,
3212};
3213
3214static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
3215{
3216 return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
3217 0, "PC Beep Playback Switch", 0);
3218}
3219#endif
3220
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003221static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3222{
3223 struct sigmatel_spec *spec = codec->spec;
3224 int wcaps, nid, i, err = 0;
3225
3226 for (i = 0; i < spec->num_muxes; i++) {
3227 nid = spec->mux_nids[i];
3228 wcaps = get_wcaps(codec, nid);
3229
3230 if (wcaps & AC_WCAP_OUT_AMP) {
3231 err = stac92xx_add_control_idx(spec,
3232 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
3233 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3234 if (err < 0)
3235 return err;
3236 }
3237 }
3238 return 0;
3239};
3240
Matthew Ranostayd9737752008-09-07 12:03:41 +02003241static const char *stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04003242 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02003243};
3244
3245static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
3246{
3247 struct sigmatel_spec *spec = codec->spec;
3248 struct hda_input_mux *spdif_mux = &spec->private_smux;
Matthew Ranostay65973632008-09-16 10:39:37 -04003249 const char **labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003250 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04003251 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003252
3253 num_cons = snd_hda_get_connections(codec,
3254 spec->smux_nids[0],
3255 con_lst,
3256 HDA_MAX_NUM_INPUTS);
Matthew Ranostay65973632008-09-16 10:39:37 -04003257 if (!num_cons)
Matthew Ranostayd9737752008-09-07 12:03:41 +02003258 return -EINVAL;
3259
Matthew Ranostay65973632008-09-16 10:39:37 -04003260 if (!labels)
3261 labels = stac92xx_spdif_labels;
3262
Matthew Ranostayd9737752008-09-07 12:03:41 +02003263 for (i = 0; i < num_cons; i++) {
Matthew Ranostay65973632008-09-16 10:39:37 -04003264 spdif_mux->items[spdif_mux->num_items].label = labels[i];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003265 spdif_mux->items[spdif_mux->num_items].index = i;
3266 spdif_mux->num_items++;
3267 }
3268
3269 return 0;
3270}
3271
Matt Porter8b657272006-10-26 17:12:59 +02003272/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01003273static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02003274 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
3275 "Digital Mic 3", "Digital Mic 4"
3276};
3277
3278/* create playback/capture controls for input pins on dmic capable codecs */
3279static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3280 const struct auto_pin_cfg *cfg)
3281{
3282 struct sigmatel_spec *spec = codec->spec;
3283 struct hda_input_mux *dimux = &spec->private_dimux;
3284 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003285 int err, i, j;
3286 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02003287
3288 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
3289 dimux->items[dimux->num_items].index = 0;
3290 dimux->num_items++;
3291
3292 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003293 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02003294 int index;
3295 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003296 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02003297 unsigned int def_conf;
3298
3299 def_conf = snd_hda_codec_read(codec,
3300 spec->dmic_nids[i],
3301 0,
3302 AC_VERB_GET_CONFIG_DEFAULT,
3303 0);
3304 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
3305 continue;
3306
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003307 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02003308 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003309 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02003310 con_lst,
3311 HDA_MAX_NUM_INPUTS);
3312 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003313 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02003314 index = j;
3315 goto found;
3316 }
3317 continue;
3318found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003319 wcaps = get_wcaps(codec, nid) &
3320 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003321
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003322 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003323 sprintf(name, "%s Capture Volume",
3324 stac92xx_dmic_labels[dimux->num_items]);
3325
3326 err = stac92xx_add_control(spec,
3327 STAC_CTL_WIDGET_VOL,
3328 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003329 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3330 (wcaps & AC_WCAP_OUT_AMP) ?
3331 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003332 if (err < 0)
3333 return err;
3334 }
3335
Matt Porter8b657272006-10-26 17:12:59 +02003336 dimux->items[dimux->num_items].label =
3337 stac92xx_dmic_labels[dimux->num_items];
3338 dimux->items[dimux->num_items].index = index;
3339 dimux->num_items++;
3340 }
3341
3342 return 0;
3343}
3344
Mattc7d4b2f2005-06-27 14:59:41 +02003345/* create playback/capture controls for input pins */
3346static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3347{
3348 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003349 struct hda_input_mux *imux = &spec->private_imux;
3350 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3351 int i, j, k;
3352
3353 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003354 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003355
Takashi Iwai314634b2006-09-21 11:56:18 +02003356 if (!cfg->input_pins[i])
3357 continue;
3358 index = -1;
3359 for (j = 0; j < spec->num_muxes; j++) {
3360 int num_cons;
3361 num_cons = snd_hda_get_connections(codec,
3362 spec->mux_nids[j],
3363 con_lst,
3364 HDA_MAX_NUM_INPUTS);
3365 for (k = 0; k < num_cons; k++)
3366 if (con_lst[k] == cfg->input_pins[i]) {
3367 index = k;
3368 goto found;
3369 }
Mattc7d4b2f2005-06-27 14:59:41 +02003370 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003371 continue;
3372 found:
3373 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3374 imux->items[imux->num_items].index = index;
3375 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003376 }
3377
Steve Longerbeam7b043892007-05-03 20:50:03 +02003378 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003379 /*
3380 * Set the current input for the muxes.
3381 * The STAC9221 has two input muxes with identical source
3382 * NID lists. Hopefully this won't get confused.
3383 */
3384 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003385 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3386 AC_VERB_SET_CONNECT_SEL,
3387 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003388 }
3389 }
3390
Mattc7d4b2f2005-06-27 14:59:41 +02003391 return 0;
3392}
3393
Mattc7d4b2f2005-06-27 14:59:41 +02003394static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3395{
3396 struct sigmatel_spec *spec = codec->spec;
3397 int i;
3398
3399 for (i = 0; i < spec->autocfg.line_outs; i++) {
3400 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3401 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3402 }
3403}
3404
3405static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3406{
3407 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003408 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003409
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003410 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3411 hda_nid_t pin;
3412 pin = spec->autocfg.hp_pins[i];
3413 if (pin) /* connect to front */
3414 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3415 }
3416 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3417 hda_nid_t pin;
3418 pin = spec->autocfg.speaker_pins[i];
3419 if (pin) /* connect to front */
3420 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3421 }
Mattc7d4b2f2005-06-27 14:59:41 +02003422}
3423
Matt Porter3cc08dc2006-01-23 15:27:49 +01003424static 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 +02003425{
3426 struct sigmatel_spec *spec = codec->spec;
3427 int err;
3428
Matt Porter8b657272006-10-26 17:12:59 +02003429 if ((err = snd_hda_parse_pin_def_config(codec,
3430 &spec->autocfg,
3431 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003432 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003433 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003434 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003435
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003436 /* If we have no real line-out pin and multiple hp-outs, HPs should
3437 * be set up as multi-channel outputs.
3438 */
3439 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3440 spec->autocfg.hp_outs > 1) {
3441 /* Copy hp_outs to line_outs, backup line_outs in
3442 * speaker_outs so that the following routines can handle
3443 * HP pins as primary outputs.
3444 */
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003445 snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003446 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3447 sizeof(spec->autocfg.line_out_pins));
3448 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3449 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3450 sizeof(spec->autocfg.hp_pins));
3451 spec->autocfg.line_outs = spec->autocfg.hp_outs;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003452 spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
3453 spec->autocfg.hp_outs = 0;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003454 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003455 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003456 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3457 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003458 u32 caps = query_amp_caps(codec,
3459 spec->autocfg.mono_out_pin, dir);
3460 hda_nid_t conn_list[1];
3461
3462 /* get the mixer node and then the mono mux if it exists */
3463 if (snd_hda_get_connections(codec,
3464 spec->autocfg.mono_out_pin, conn_list, 1) &&
3465 snd_hda_get_connections(codec, conn_list[0],
3466 conn_list, 1)) {
3467
3468 int wcaps = get_wcaps(codec, conn_list[0]);
3469 int wid_type = (wcaps & AC_WCAP_TYPE)
3470 >> AC_WCAP_TYPE_SHIFT;
3471 /* LR swap check, some stac925x have a mux that
3472 * changes the DACs output path instead of the
3473 * mono-mux path.
3474 */
3475 if (wid_type == AC_WID_AUD_SEL &&
3476 !(wcaps & AC_WCAP_LR_SWAP))
3477 spec->mono_nid = conn_list[0];
3478 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003479 if (dir) {
3480 hda_nid_t nid = spec->autocfg.mono_out_pin;
3481
3482 /* most mono outs have a least a mute/unmute switch */
3483 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3484 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3485 "Mono Playback Switch",
3486 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003487 if (err < 0)
3488 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003489 /* check for volume support for the amp */
3490 if ((caps & AC_AMPCAP_NUM_STEPS)
3491 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3492 err = stac92xx_add_control(spec,
3493 STAC_CTL_WIDGET_VOL,
3494 "Mono Playback Volume",
3495 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3496 if (err < 0)
3497 return err;
3498 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003499 }
3500
3501 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3502 AC_PINCTL_OUT_EN);
3503 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003504
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003505 if (!spec->multiout.num_dacs) {
3506 err = stac92xx_auto_fill_dac_nids(codec);
3507 if (err < 0)
Takashi Iwai19039bd2006-06-28 15:52:16 +02003508 return err;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003509 }
Mattc7d4b2f2005-06-27 14:59:41 +02003510
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003511 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3512
3513 if (err < 0)
3514 return err;
3515
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003516 /* setup analog beep controls */
3517 if (spec->anabeep_nid > 0) {
3518 err = stac92xx_auto_create_beep_ctls(codec,
3519 spec->anabeep_nid);
3520 if (err < 0)
3521 return err;
3522 }
3523
3524 /* setup digital beep controls and input device */
3525#ifdef CONFIG_SND_HDA_INPUT_BEEP
3526 if (spec->digbeep_nid > 0) {
3527 hda_nid_t nid = spec->digbeep_nid;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003528 unsigned int caps;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003529
3530 err = stac92xx_auto_create_beep_ctls(codec, nid);
3531 if (err < 0)
3532 return err;
3533 err = snd_hda_attach_beep_device(codec, nid);
3534 if (err < 0)
3535 return err;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003536 /* if no beep switch is available, make its own one */
3537 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3538 if (codec->beep &&
3539 !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
3540 err = stac92xx_beep_switch_ctl(codec);
3541 if (err < 0)
3542 return err;
3543 }
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003544 }
3545#endif
3546
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003547 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3548
3549 if (err < 0)
3550 return err;
3551
3552 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3553
3554 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003555 return err;
3556
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003557 if (spec->mono_nid > 0) {
3558 err = stac92xx_auto_create_mono_output_ctls(codec);
3559 if (err < 0)
3560 return err;
3561 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003562 if (spec->num_amps > 0) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003563 err = stac92xx_auto_create_amp_output_ctls(codec);
3564 if (err < 0)
3565 return err;
3566 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003567 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02003568 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3569 &spec->autocfg)) < 0)
3570 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003571 if (spec->num_muxes > 0) {
3572 err = stac92xx_auto_create_mux_input_ctls(codec);
3573 if (err < 0)
3574 return err;
3575 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003576 if (spec->num_smuxes > 0) {
3577 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3578 if (err < 0)
3579 return err;
3580 }
Matt Porter8b657272006-10-26 17:12:59 +02003581
Mattc7d4b2f2005-06-27 14:59:41 +02003582 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003583 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003584 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003585
Takashi Iwai82bc9552006-03-21 11:24:42 +01003586 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003587 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003588 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003589 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003590
Takashi Iwai603c4012008-07-30 15:01:44 +02003591 if (spec->kctls.list)
3592 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003593
3594 spec->input_mux = &spec->private_imux;
Matthew Ranostayf8ccbf62008-12-20 17:36:28 -05003595 if (!spec->dinput_mux)
3596 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003597 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003598 spec->mono_mux = &spec->private_mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -04003599 spec->amp_mux = &spec->private_amp_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003600 return 1;
3601}
3602
Takashi Iwai82bc9552006-03-21 11:24:42 +01003603/* add playback controls for HP output */
3604static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3605 struct auto_pin_cfg *cfg)
3606{
3607 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003608 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003609 unsigned int wid_caps;
3610
3611 if (! pin)
3612 return 0;
3613
3614 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003615 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003616 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003617
3618 return 0;
3619}
3620
Richard Fish160ea0d2006-09-06 13:58:25 +02003621/* add playback controls for LFE output */
3622static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3623 struct auto_pin_cfg *cfg)
3624{
3625 struct sigmatel_spec *spec = codec->spec;
3626 int err;
3627 hda_nid_t lfe_pin = 0x0;
3628 int i;
3629
3630 /*
3631 * search speaker outs and line outs for a mono speaker pin
3632 * with an amp. If one is found, add LFE controls
3633 * for it.
3634 */
3635 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3636 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003637 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003638 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3639 if (wcaps == AC_WCAP_OUT_AMP)
3640 /* found a mono speaker with an amp, must be lfe */
3641 lfe_pin = pin;
3642 }
3643
3644 /* if speaker_outs is 0, then speakers may be in line_outs */
3645 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3646 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3647 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003648 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003649 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003650 AC_VERB_GET_CONFIG_DEFAULT,
3651 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003652 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003653 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003654 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3655 if (wcaps == AC_WCAP_OUT_AMP)
3656 /* found a mono speaker with an amp,
3657 must be lfe */
3658 lfe_pin = pin;
3659 }
3660 }
3661 }
3662
3663 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003664 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003665 if (err < 0)
3666 return err;
3667 }
3668
3669 return 0;
3670}
3671
Mattc7d4b2f2005-06-27 14:59:41 +02003672static int stac9200_parse_auto_config(struct hda_codec *codec)
3673{
3674 struct sigmatel_spec *spec = codec->spec;
3675 int err;
3676
Kailang Yangdf694da2005-12-05 19:42:22 +01003677 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003678 return err;
3679
3680 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3681 return err;
3682
Takashi Iwai82bc9552006-03-21 11:24:42 +01003683 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3684 return err;
3685
Richard Fish160ea0d2006-09-06 13:58:25 +02003686 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3687 return err;
3688
Takashi Iwai355a0ec2008-11-11 16:46:19 +01003689 if (spec->num_muxes > 0) {
3690 err = stac92xx_auto_create_mux_input_ctls(codec);
3691 if (err < 0)
3692 return err;
3693 }
3694
Takashi Iwai82bc9552006-03-21 11:24:42 +01003695 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003696 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003697 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003698 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003699
Takashi Iwai603c4012008-07-30 15:01:44 +02003700 if (spec->kctls.list)
3701 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003702
3703 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003704 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003705
3706 return 1;
3707}
3708
Sam Revitch62fe78e2006-05-10 15:09:17 +02003709/*
3710 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3711 * funky external mute control using GPIO pins.
3712 */
3713
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003714static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003715 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003716{
3717 unsigned int gpiostate, gpiomask, gpiodir;
3718
3719 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3720 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003721 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003722
3723 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3724 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003725 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003726
3727 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3728 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003729 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003730
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003731 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003732 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3733
3734 snd_hda_codec_write(codec, codec->afg, 0,
3735 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003736 snd_hda_codec_read(codec, codec->afg, 0,
3737 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003738
3739 msleep(1);
3740
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003741 snd_hda_codec_read(codec, codec->afg, 0,
3742 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003743}
3744
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003745static int stac92xx_add_jack(struct hda_codec *codec,
3746 hda_nid_t nid, int type)
3747{
Takashi Iwaie4973e12008-11-18 09:32:42 +01003748#ifdef CONFIG_SND_JACK
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003749 struct sigmatel_spec *spec = codec->spec;
3750 struct sigmatel_jack *jack;
3751 int def_conf = snd_hda_codec_read(codec, nid,
3752 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
3753 int connectivity = get_defcfg_connect(def_conf);
3754 char name[32];
3755
3756 if (connectivity && connectivity != AC_JACK_PORT_FIXED)
3757 return 0;
3758
3759 snd_array_init(&spec->jacks, sizeof(*jack), 32);
3760 jack = snd_array_new(&spec->jacks);
3761 if (!jack)
3762 return -ENOMEM;
3763 jack->nid = nid;
3764 jack->type = type;
3765
3766 sprintf(name, "%s at %s %s Jack",
3767 snd_hda_get_jack_type(def_conf),
3768 snd_hda_get_jack_connectivity(def_conf),
3769 snd_hda_get_jack_location(def_conf));
3770
3771 return snd_jack_new(codec->bus->card, name, type, &jack->jack);
Takashi Iwaie4973e12008-11-18 09:32:42 +01003772#else
3773 return 0;
3774#endif
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003775}
3776
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003777static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
3778 unsigned char type, int data)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003779{
3780 struct sigmatel_event *event;
3781
3782 snd_array_init(&spec->events, sizeof(*event), 32);
3783 event = snd_array_new(&spec->events);
3784 if (!event)
3785 return -ENOMEM;
3786 event->nid = nid;
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003787 event->type = type;
3788 event->tag = spec->events.used;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003789 event->data = data;
3790
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003791 return event->tag;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003792}
3793
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003794static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
3795 hda_nid_t nid, unsigned char type)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003796{
3797 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003798 struct sigmatel_event *event = spec->events.list;
3799 int i;
3800
3801 for (i = 0; i < spec->events.used; i++, event++) {
3802 if (event->nid == nid && event->type == type)
3803 return event;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003804 }
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003805 return NULL;
3806}
3807
3808static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
3809 unsigned char tag)
3810{
3811 struct sigmatel_spec *spec = codec->spec;
3812 struct sigmatel_event *event = spec->events.list;
3813 int i;
3814
3815 for (i = 0; i < spec->events.used; i++, event++) {
3816 if (event->tag == tag)
3817 return event;
3818 }
3819 return NULL;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003820}
3821
Takashi Iwai314634b2006-09-21 11:56:18 +02003822static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003823 unsigned int type)
Takashi Iwai314634b2006-09-21 11:56:18 +02003824{
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003825 struct sigmatel_event *event;
3826 int tag;
3827
3828 if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
3829 return;
3830 event = stac_get_event(codec, nid, type);
3831 if (event)
3832 tag = event->tag;
3833 else
3834 tag = stac_add_event(codec->spec, nid, type, 0);
3835 if (tag < 0)
3836 return;
3837 snd_hda_codec_write_cache(codec, nid, 0,
3838 AC_VERB_SET_UNSOLICITED_ENABLE,
3839 AC_USRSP_EN | tag);
Takashi Iwai314634b2006-09-21 11:56:18 +02003840}
3841
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003842static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3843{
3844 int i;
3845 for (i = 0; i < cfg->hp_outs; i++)
3846 if (cfg->hp_pins[i] == nid)
3847 return 1; /* nid is a HP-Out */
3848
3849 return 0; /* nid is not a HP-Out */
3850};
3851
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003852static void stac92xx_power_down(struct hda_codec *codec)
3853{
3854 struct sigmatel_spec *spec = codec->spec;
3855
3856 /* power down inactive DACs */
3857 hda_nid_t *dac;
3858 for (dac = spec->dac_list; *dac; dac++)
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003859 if (!check_all_dac_nids(spec, *dac))
Takashi Iwai8c2f7672008-12-01 11:54:35 +01003860 snd_hda_codec_write(codec, *dac, 0,
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003861 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3862}
3863
Takashi Iwaif73d3582008-11-25 08:21:51 +01003864static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
3865 int enable);
3866
Mattc7d4b2f2005-06-27 14:59:41 +02003867static int stac92xx_init(struct hda_codec *codec)
3868{
3869 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003870 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaif73d3582008-11-25 08:21:51 +01003871 unsigned int gpio;
Takashi Iwaie4973e12008-11-18 09:32:42 +01003872 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003873
Mattc7d4b2f2005-06-27 14:59:41 +02003874 snd_hda_sequence_write(codec, spec->init);
3875
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003876 /* power down adcs initially */
3877 if (spec->powerdown_adcs)
3878 for (i = 0; i < spec->num_adcs; i++)
Takashi Iwai8c2f7672008-12-01 11:54:35 +01003879 snd_hda_codec_write(codec,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003880 spec->adc_nids[i], 0,
3881 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwaif73d3582008-11-25 08:21:51 +01003882
3883 /* set up GPIO */
3884 gpio = spec->gpio_data;
3885 /* turn on EAPD statically when spec->eapd_switch isn't set.
3886 * otherwise, unsol event will turn it on/off dynamically
3887 */
3888 if (!spec->eapd_switch)
3889 gpio |= spec->eapd_mask;
3890 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
3891
Takashi Iwai82bc9552006-03-21 11:24:42 +01003892 /* set up pins */
3893 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003894 /* Enable unsolicited responses on the HP widget */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003895 for (i = 0; i < cfg->hp_outs; i++) {
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003896 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003897 enable_pin_detect(codec, nid, STAC_HP_EVENT);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003898 }
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003899 /* force to enable the first line-out; the others are set up
3900 * in unsol_event
3901 */
3902 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003903 AC_PINCTL_OUT_EN);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003904 /* fake event to set up pins */
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003905 stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
3906 STAC_HP_EVENT);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003907 } else {
3908 stac92xx_auto_init_multi_out(codec);
3909 stac92xx_auto_init_hp_out(codec);
Takashi Iwai12dde4c2008-12-05 13:09:27 +01003910 for (i = 0; i < cfg->hp_outs; i++)
3911 stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003912 }
3913 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003914 hda_nid_t nid = cfg->input_pins[i];
3915 if (nid) {
Takashi Iwai12dde4c2008-12-05 13:09:27 +01003916 unsigned int pinctl, conf;
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01003917 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
3918 /* for mic pins, force to initialize */
3919 pinctl = stac92xx_get_vref(codec, nid);
Takashi Iwai12dde4c2008-12-05 13:09:27 +01003920 pinctl |= AC_PINCTL_IN_EN;
3921 stac92xx_auto_set_pinctl(codec, nid, pinctl);
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01003922 } else {
3923 pinctl = snd_hda_codec_read(codec, nid, 0,
3924 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3925 /* if PINCTL already set then skip */
Takashi Iwai12dde4c2008-12-05 13:09:27 +01003926 if (!(pinctl & AC_PINCTL_IN_EN)) {
3927 pinctl |= AC_PINCTL_IN_EN;
3928 stac92xx_auto_set_pinctl(codec, nid,
3929 pinctl);
3930 }
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01003931 }
Takashi Iwai12dde4c2008-12-05 13:09:27 +01003932 conf = snd_hda_codec_read(codec, nid, 0,
3933 AC_VERB_GET_CONFIG_DEFAULT, 0);
3934 if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
3935 enable_pin_detect(codec, nid,
3936 STAC_INSERT_EVENT);
3937 stac_issue_unsol_event(codec, nid,
3938 STAC_INSERT_EVENT);
3939 }
Takashi Iwaic960a032006-03-23 17:06:28 +01003940 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003941 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003942 for (i = 0; i < spec->num_dmics; i++)
3943 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3944 AC_PINCTL_IN_EN);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003945 if (cfg->dig_out_pin)
3946 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3947 AC_PINCTL_OUT_EN);
3948 if (cfg->dig_in_pin)
3949 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3950 AC_PINCTL_IN_EN);
Takashi Iwaif73d3582008-11-25 08:21:51 +01003951 for (i = 0; i < spec->num_pwrs; i++) {
3952 hda_nid_t nid = spec->pwr_nids[i];
3953 int pinctl, def_conf;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003954
Takashi Iwaieb632122008-12-19 16:39:48 +01003955 /* power on when no jack detection is available */
3956 if (!spec->hp_detect) {
3957 stac_toggle_power_map(codec, nid, 1);
3958 continue;
3959 }
3960
3961 if (is_nid_hp_pin(cfg, nid))
Takashi Iwaif73d3582008-11-25 08:21:51 +01003962 continue; /* already has an unsol event */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003963
Takashi Iwaif73d3582008-11-25 08:21:51 +01003964 pinctl = snd_hda_codec_read(codec, nid, 0,
3965 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3966 /* outputs are only ports capable of power management
3967 * any attempts on powering down a input port cause the
3968 * referenced VREF to act quirky.
3969 */
Takashi Iwaieb632122008-12-19 16:39:48 +01003970 if (pinctl & AC_PINCTL_IN_EN) {
3971 stac_toggle_power_map(codec, nid, 1);
Takashi Iwaif73d3582008-11-25 08:21:51 +01003972 continue;
Takashi Iwaieb632122008-12-19 16:39:48 +01003973 }
Takashi Iwaif73d3582008-11-25 08:21:51 +01003974 def_conf = snd_hda_codec_read(codec, nid, 0,
3975 AC_VERB_GET_CONFIG_DEFAULT, 0);
3976 def_conf = get_defcfg_connect(def_conf);
3977 /* skip any ports that don't have jacks since presence
3978 * detection is useless */
3979 if (def_conf != AC_JACK_PORT_COMPLEX) {
3980 if (def_conf != AC_JACK_PORT_NONE)
3981 stac_toggle_power_map(codec, nid, 1);
3982 continue;
3983 }
Takashi Iwai12dde4c2008-12-05 13:09:27 +01003984 if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) {
3985 enable_pin_detect(codec, nid, STAC_PWR_EVENT);
3986 stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
3987 }
Takashi Iwaif73d3582008-11-25 08:21:51 +01003988 }
3989 if (spec->dac_list)
3990 stac92xx_power_down(codec);
Mattc7d4b2f2005-06-27 14:59:41 +02003991 return 0;
3992}
3993
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003994static void stac92xx_free_jacks(struct hda_codec *codec)
3995{
Takashi Iwaie4973e12008-11-18 09:32:42 +01003996#ifdef CONFIG_SND_JACK
Takashi Iwaib94d35392008-11-21 09:08:06 +01003997 /* free jack instances manually when clearing/reconfiguring */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003998 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaib94d35392008-11-21 09:08:06 +01003999 if (!codec->bus->shutdown && spec->jacks.list) {
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004000 struct sigmatel_jack *jacks = spec->jacks.list;
4001 int i;
4002 for (i = 0; i < spec->jacks.used; i++)
4003 snd_device_free(codec->bus->card, &jacks[i].jack);
4004 }
4005 snd_array_free(&spec->jacks);
Takashi Iwaie4973e12008-11-18 09:32:42 +01004006#endif
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004007}
4008
Takashi Iwai603c4012008-07-30 15:01:44 +02004009static void stac92xx_free_kctls(struct hda_codec *codec)
4010{
4011 struct sigmatel_spec *spec = codec->spec;
4012
4013 if (spec->kctls.list) {
4014 struct snd_kcontrol_new *kctl = spec->kctls.list;
4015 int i;
4016 for (i = 0; i < spec->kctls.used; i++)
4017 kfree(kctl[i].name);
4018 }
4019 snd_array_free(&spec->kctls);
4020}
4021
Matt2f2f4252005-04-13 14:45:30 +02004022static void stac92xx_free(struct hda_codec *codec)
4023{
Mattc7d4b2f2005-06-27 14:59:41 +02004024 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004025
4026 if (! spec)
4027 return;
4028
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004029 kfree(spec->pin_configs);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004030 stac92xx_free_jacks(codec);
4031 snd_array_free(&spec->events);
Richard Fish11b44bb2006-08-23 18:31:34 +02004032
Mattc7d4b2f2005-06-27 14:59:41 +02004033 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004034 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02004035}
4036
Matt4e550962005-07-04 17:51:39 +02004037static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
4038 unsigned int flag)
4039{
4040 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
4041 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02004042
Takashi Iwaif9acba42007-05-29 18:01:06 +02004043 if (pin_ctl & AC_PINCTL_IN_EN) {
4044 /*
4045 * we need to check the current set-up direction of
4046 * shared input pins since they can be switched via
4047 * "xxx as Output" mixer switch
4048 */
4049 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004050 if (nid == spec->line_switch || nid == spec->mic_switch)
Takashi Iwaif9acba42007-05-29 18:01:06 +02004051 return;
4052 }
4053
Steve Longerbeam7b043892007-05-03 20:50:03 +02004054 /* if setting pin direction bits, clear the current
4055 direction bits first */
4056 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
4057 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
4058
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004059 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02004060 AC_VERB_SET_PIN_WIDGET_CONTROL,
4061 pin_ctl | flag);
4062}
4063
4064static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
4065 unsigned int flag)
4066{
4067 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
4068 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004069 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02004070 AC_VERB_SET_PIN_WIDGET_CONTROL,
4071 pin_ctl & ~flag);
4072}
4073
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01004074static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02004075{
4076 if (!nid)
4077 return 0;
4078 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01004079 & (1 << 31))
4080 return 1;
Takashi Iwai314634b2006-09-21 11:56:18 +02004081 return 0;
4082}
4083
Takashi Iwaid7a89432008-11-12 09:48:04 +01004084/* return non-zero if the hp-pin of the given array index isn't
4085 * a jack-detection target
4086 */
4087static int no_hp_sensing(struct sigmatel_spec *spec, int i)
4088{
4089 struct auto_pin_cfg *cfg = &spec->autocfg;
4090
4091 /* ignore sensing of shared line and mic jacks */
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004092 if (cfg->hp_pins[i] == spec->line_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004093 return 1;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004094 if (cfg->hp_pins[i] == spec->mic_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004095 return 1;
4096 /* ignore if the pin is set as line-out */
4097 if (cfg->hp_pins[i] == spec->hp_switch)
4098 return 1;
4099 return 0;
4100}
4101
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004102static void stac92xx_hp_detect(struct hda_codec *codec)
Matt4e550962005-07-04 17:51:39 +02004103{
4104 struct sigmatel_spec *spec = codec->spec;
4105 struct auto_pin_cfg *cfg = &spec->autocfg;
4106 int i, presence;
4107
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004108 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004109 if (spec->gpio_mute)
4110 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
4111 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
4112
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004113 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02004114 if (presence)
4115 break;
Takashi Iwaid7a89432008-11-12 09:48:04 +01004116 if (no_hp_sensing(spec, i))
4117 continue;
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01004118 presence = get_pin_presence(codec, cfg->hp_pins[i]);
4119 if (presence) {
4120 unsigned int pinctl;
4121 pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
4122 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4123 if (pinctl & AC_PINCTL_IN_EN)
4124 presence = 0; /* mic- or line-input */
4125 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004126 }
Matt4e550962005-07-04 17:51:39 +02004127
4128 if (presence) {
Takashi Iwaid7a89432008-11-12 09:48:04 +01004129 /* disable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02004130 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004131 stac92xx_reset_pinctl(codec, spec->hp_switch,
4132 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02004133 for (i = 0; i < cfg->line_outs; i++)
4134 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
4135 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004136 for (i = 0; i < cfg->speaker_outs; i++)
4137 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
4138 AC_PINCTL_OUT_EN);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004139 if (spec->eapd_mask && spec->eapd_switch)
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004140 stac_gpio_set(codec, spec->gpio_mask,
4141 spec->gpio_dir, spec->gpio_data &
4142 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02004143 } else {
Takashi Iwaid7a89432008-11-12 09:48:04 +01004144 /* enable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02004145 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004146 stac92xx_set_pinctl(codec, spec->hp_switch,
4147 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02004148 for (i = 0; i < cfg->line_outs; i++)
4149 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
4150 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004151 for (i = 0; i < cfg->speaker_outs; i++)
4152 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
4153 AC_PINCTL_OUT_EN);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004154 if (spec->eapd_mask && spec->eapd_switch)
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004155 stac_gpio_set(codec, spec->gpio_mask,
4156 spec->gpio_dir, spec->gpio_data |
4157 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02004158 }
Takashi Iwaid7a89432008-11-12 09:48:04 +01004159 /* toggle hp outs */
4160 for (i = 0; i < cfg->hp_outs; i++) {
4161 unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
4162 if (no_hp_sensing(spec, i))
4163 continue;
4164 if (presence)
4165 stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
4166 else
4167 stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
4168 }
Matt4e550962005-07-04 17:51:39 +02004169}
4170
Takashi Iwaif73d3582008-11-25 08:21:51 +01004171static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
4172 int enable)
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004173{
4174 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaif73d3582008-11-25 08:21:51 +01004175 unsigned int idx, val;
4176
4177 for (idx = 0; idx < spec->num_pwrs; idx++) {
4178 if (spec->pwr_nids[idx] == nid)
4179 break;
4180 }
4181 if (idx >= spec->num_pwrs)
4182 return;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004183
4184 /* several codecs have two power down bits */
4185 if (spec->pwr_mapping)
4186 idx = spec->pwr_mapping[idx];
4187 else
4188 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004189
Takashi Iwaif73d3582008-11-25 08:21:51 +01004190 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
4191 if (enable)
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004192 val &= ~idx;
4193 else
4194 val |= idx;
4195
4196 /* power down unused output ports */
4197 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004198}
4199
Takashi Iwaif73d3582008-11-25 08:21:51 +01004200static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
4201{
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01004202 stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
Takashi Iwaif73d3582008-11-25 08:21:51 +01004203}
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004204
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004205static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
4206{
4207 struct sigmatel_spec *spec = codec->spec;
4208 struct sigmatel_jack *jacks = spec->jacks.list;
4209
4210 if (jacks) {
4211 int i;
4212 for (i = 0; i < spec->jacks.used; i++) {
4213 if (jacks->nid == nid) {
4214 unsigned int pin_ctl =
4215 snd_hda_codec_read(codec, nid,
4216 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
4217 0x00);
4218 int type = jacks->type;
4219 if (type == (SND_JACK_LINEOUT
4220 | SND_JACK_HEADPHONE))
4221 type = (pin_ctl & AC_PINCTL_HP_EN)
4222 ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
4223 snd_jack_report(jacks->jack,
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01004224 get_pin_presence(codec, nid)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004225 ? type : 0);
4226 }
4227 jacks++;
4228 }
4229 }
4230}
Matt2f2f4252005-04-13 14:45:30 +02004231
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004232static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
4233 unsigned char type)
4234{
4235 struct sigmatel_event *event = stac_get_event(codec, nid, type);
4236 if (!event)
4237 return;
4238 codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
4239}
4240
Takashi Iwai314634b2006-09-21 11:56:18 +02004241static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
4242{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004243 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004244 struct sigmatel_event *event;
4245 int tag, data;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004246
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004247 tag = (res >> 26) & 0x7f;
4248 event = stac_get_event_from_tag(codec, tag);
4249 if (!event)
4250 return;
4251
4252 switch (event->type) {
Takashi Iwai314634b2006-09-21 11:56:18 +02004253 case STAC_HP_EVENT:
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004254 stac92xx_hp_detect(codec);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004255 /* fallthru */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004256 case STAC_INSERT_EVENT:
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004257 case STAC_PWR_EVENT:
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004258 if (spec->num_pwrs > 0)
4259 stac92xx_pin_sense(codec, event->nid);
4260 stac92xx_report_jack(codec, event->nid);
Matthew Ranostay72474be2008-10-09 09:32:17 -04004261 break;
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004262 case STAC_VREF_EVENT:
4263 data = snd_hda_codec_read(codec, codec->afg, 0,
4264 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay72474be2008-10-09 09:32:17 -04004265 /* toggle VREF state based on GPIOx status */
4266 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004267 !!(data & (1 << event->data)));
Matthew Ranostay72474be2008-10-09 09:32:17 -04004268 break;
Takashi Iwai314634b2006-09-21 11:56:18 +02004269 }
4270}
4271
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01004272#ifdef CONFIG_PROC_FS
4273static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
4274 struct hda_codec *codec, hda_nid_t nid)
4275{
4276 if (nid == codec->afg)
4277 snd_iprintf(buffer, "Power-Map: 0x%02x\n",
4278 snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
4279}
4280
4281static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
4282 struct hda_codec *codec,
4283 unsigned int verb)
4284{
4285 snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
4286 snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
4287}
4288
4289/* stac92hd71bxx, stac92hd73xx */
4290static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
4291 struct hda_codec *codec, hda_nid_t nid)
4292{
4293 stac92hd_proc_hook(buffer, codec, nid);
4294 if (nid == codec->afg)
4295 analog_loop_proc_hook(buffer, codec, 0xfa0);
4296}
4297
4298static void stac9205_proc_hook(struct snd_info_buffer *buffer,
4299 struct hda_codec *codec, hda_nid_t nid)
4300{
4301 if (nid == codec->afg)
4302 analog_loop_proc_hook(buffer, codec, 0xfe0);
4303}
4304
4305static void stac927x_proc_hook(struct snd_info_buffer *buffer,
4306 struct hda_codec *codec, hda_nid_t nid)
4307{
4308 if (nid == codec->afg)
4309 analog_loop_proc_hook(buffer, codec, 0xfeb);
4310}
4311#else
4312#define stac92hd_proc_hook NULL
4313#define stac92hd7x_proc_hook NULL
4314#define stac9205_proc_hook NULL
4315#define stac927x_proc_hook NULL
4316#endif
4317
Takashi Iwaicb53c622007-08-10 17:21:45 +02004318#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004319static int stac92xx_resume(struct hda_codec *codec)
4320{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004321 struct sigmatel_spec *spec = codec->spec;
4322
Richard Fish11b44bb2006-08-23 18:31:34 +02004323 stac92xx_set_config_regs(codec);
Takashi Iwai2c885872008-11-18 09:36:55 +01004324 stac92xx_init(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004325 snd_hda_codec_resume_amp(codec);
4326 snd_hda_codec_resume_cache(codec);
Takashi Iwai2c885872008-11-18 09:36:55 +01004327 /* fake event to set up pins again to override cached values */
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004328 if (spec->hp_detect)
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004329 stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
4330 STAC_HP_EVENT);
Mattff6fdc32005-06-27 15:06:52 +02004331 return 0;
4332}
Matthew Ranostayc6798d22008-11-18 20:54:17 -05004333
4334static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
4335{
4336 struct sigmatel_spec *spec = codec->spec;
4337 if (spec->eapd_mask)
4338 stac_gpio_set(codec, spec->gpio_mask,
4339 spec->gpio_dir, spec->gpio_data &
4340 ~spec->eapd_mask);
4341 return 0;
4342}
Mattff6fdc32005-06-27 15:06:52 +02004343#endif
4344
Matt2f2f4252005-04-13 14:45:30 +02004345static struct hda_codec_ops stac92xx_patch_ops = {
4346 .build_controls = stac92xx_build_controls,
4347 .build_pcms = stac92xx_build_pcms,
4348 .init = stac92xx_init,
4349 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02004350 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004351#ifdef SND_HDA_NEEDS_RESUME
Matthew Ranostayc6798d22008-11-18 20:54:17 -05004352 .suspend = stac92xx_suspend,
Mattff6fdc32005-06-27 15:06:52 +02004353 .resume = stac92xx_resume,
4354#endif
Matt2f2f4252005-04-13 14:45:30 +02004355};
4356
4357static int patch_stac9200(struct hda_codec *codec)
4358{
4359 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004360 int err;
Matt2f2f4252005-04-13 14:45:30 +02004361
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004362 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004363 if (spec == NULL)
4364 return -ENOMEM;
4365
4366 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004367 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004368 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004369 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
4370 stac9200_models,
4371 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02004372 if (spec->board_config < 0) {
4373 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
4374 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004375 } else
4376 err = stac_save_pin_cfgs(codec,
4377 stac9200_brd_tbl[spec->board_config]);
4378 if (err < 0) {
4379 stac92xx_free(codec);
4380 return err;
Matt Porter403d1942005-11-29 15:00:51 +01004381 }
Matt2f2f4252005-04-13 14:45:30 +02004382
4383 spec->multiout.max_channels = 2;
4384 spec->multiout.num_dacs = 1;
4385 spec->multiout.dac_nids = stac9200_dac_nids;
4386 spec->adc_nids = stac9200_adc_nids;
4387 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02004388 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02004389 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004390 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004391 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004392
Tobin Davisbf277782008-02-03 20:31:47 +01004393 if (spec->board_config == STAC_9200_GATEWAY ||
4394 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02004395 spec->init = stac9200_eapd_init;
4396 else
4397 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004398 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004399
Takashi Iwai117f2572008-03-18 09:53:23 +01004400 if (spec->board_config == STAC_9200_PANASONIC) {
4401 spec->gpio_mask = spec->gpio_dir = 0x09;
4402 spec->gpio_data = 0x00;
4403 }
4404
Mattc7d4b2f2005-06-27 14:59:41 +02004405 err = stac9200_parse_auto_config(codec);
4406 if (err < 0) {
4407 stac92xx_free(codec);
4408 return err;
4409 }
Matt2f2f4252005-04-13 14:45:30 +02004410
4411 codec->patch_ops = stac92xx_patch_ops;
4412
4413 return 0;
4414}
4415
Tobin Davis8e21c342007-01-08 11:04:17 +01004416static int patch_stac925x(struct hda_codec *codec)
4417{
4418 struct sigmatel_spec *spec;
4419 int err;
4420
4421 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4422 if (spec == NULL)
4423 return -ENOMEM;
4424
4425 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004426 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01004427 spec->pin_nids = stac925x_pin_nids;
4428 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
4429 stac925x_models,
4430 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004431 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01004432 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02004433 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
4434 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01004435 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004436 } else
4437 err = stac_save_pin_cfgs(codec,
4438 stac925x_brd_tbl[spec->board_config]);
4439 if (err < 0) {
4440 stac92xx_free(codec);
4441 return err;
Tobin Davis8e21c342007-01-08 11:04:17 +01004442 }
4443
4444 spec->multiout.max_channels = 2;
4445 spec->multiout.num_dacs = 1;
4446 spec->multiout.dac_nids = stac925x_dac_nids;
4447 spec->adc_nids = stac925x_adc_nids;
4448 spec->mux_nids = stac925x_mux_nids;
4449 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004450 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004451 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02004452 switch (codec->vendor_id) {
4453 case 0x83847632: /* STAC9202 */
4454 case 0x83847633: /* STAC9202D */
4455 case 0x83847636: /* STAC9251 */
4456 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02004457 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02004458 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004459 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
4460 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02004461 break;
4462 default:
4463 spec->num_dmics = 0;
4464 break;
4465 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004466
4467 spec->init = stac925x_core_init;
4468 spec->mixer = stac925x_mixer;
4469
4470 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004471 if (!err) {
4472 if (spec->board_config < 0) {
4473 printk(KERN_WARNING "hda_codec: No auto-config is "
4474 "available, default to model=ref\n");
4475 spec->board_config = STAC_925x_REF;
4476 goto again;
4477 }
4478 err = -EINVAL;
4479 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004480 if (err < 0) {
4481 stac92xx_free(codec);
4482 return err;
4483 }
4484
4485 codec->patch_ops = stac92xx_patch_ops;
4486
4487 return 0;
4488}
4489
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004490static struct hda_input_mux stac92hd73xx_dmux = {
4491 .num_items = 4,
4492 .items = {
4493 { "Analog Inputs", 0x0b },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004494 { "Digital Mic 1", 0x09 },
4495 { "Digital Mic 2", 0x0a },
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004496 { "CD", 0x08 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004497 }
4498};
4499
4500static int patch_stac92hd73xx(struct hda_codec *codec)
4501{
4502 struct sigmatel_spec *spec;
4503 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
4504 int err = 0;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004505 int num_dacs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004506
4507 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4508 if (spec == NULL)
4509 return -ENOMEM;
4510
4511 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02004512 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004513 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
4514 spec->pin_nids = stac92hd73xx_pin_nids;
4515 spec->board_config = snd_hda_check_board_config(codec,
4516 STAC_92HD73XX_MODELS,
4517 stac92hd73xx_models,
4518 stac92hd73xx_cfg_tbl);
4519again:
4520 if (spec->board_config < 0) {
4521 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4522 " STAC92HD73XX, using BIOS defaults\n");
4523 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004524 } else
4525 err = stac_save_pin_cfgs(codec,
4526 stac92hd73xx_brd_tbl[spec->board_config]);
4527 if (err < 0) {
4528 stac92xx_free(codec);
4529 return err;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004530 }
4531
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004532 num_dacs = snd_hda_get_connections(codec, 0x0a,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004533 conn, STAC92HD73_DAC_COUNT + 2) - 1;
4534
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004535 if (num_dacs < 3 || num_dacs > 5) {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004536 printk(KERN_WARNING "hda_codec: Could not determine "
4537 "number of channels defaulting to DAC count\n");
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004538 num_dacs = STAC92HD73_DAC_COUNT;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004539 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004540 switch (num_dacs) {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004541 case 0x3: /* 6 Channel */
4542 spec->mixer = stac92hd73xx_6ch_mixer;
4543 spec->init = stac92hd73xx_6ch_core_init;
4544 break;
4545 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004546 spec->mixer = stac92hd73xx_8ch_mixer;
4547 spec->init = stac92hd73xx_8ch_core_init;
4548 break;
4549 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004550 spec->mixer = stac92hd73xx_10ch_mixer;
4551 spec->init = stac92hd73xx_10ch_core_init;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004552 }
4553 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004554
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004555 spec->aloopback_mask = 0x01;
4556 spec->aloopback_shift = 8;
4557
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004558 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004559 spec->mux_nids = stac92hd73xx_mux_nids;
4560 spec->adc_nids = stac92hd73xx_adc_nids;
4561 spec->dmic_nids = stac92hd73xx_dmic_nids;
4562 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004563 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostay89385032008-09-11 09:49:39 -04004564 spec->amp_nids = stac92hd73xx_amp_nids;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004565 spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004566
4567 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
4568 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004569 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004570 memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
4571 sizeof(stac92hd73xx_dmux));
4572
Matthew Ranostaya7662642008-02-21 07:51:14 +01004573 switch (spec->board_config) {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004574 case STAC_DELL_EQ:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004575 spec->init = dell_eq_core_init;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004576 /* fallthru */
Takashi Iwai661cd8f2008-11-25 15:18:29 +01004577 case STAC_DELL_M6_AMIC:
4578 case STAC_DELL_M6_DMIC:
4579 case STAC_DELL_M6_BOTH:
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004580 spec->num_smuxes = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004581 spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
4582 spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004583 spec->eapd_switch = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004584 spec->num_amps = 1;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004585
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004586 if (spec->board_config != STAC_DELL_EQ)
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004587 spec->init = dell_m6_core_init;
Takashi Iwai661cd8f2008-11-25 15:18:29 +01004588 switch (spec->board_config) {
4589 case STAC_DELL_M6_AMIC: /* Analog Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004590 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4591 spec->num_dmics = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004592 spec->private_dimux.num_items = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004593 break;
Takashi Iwai661cd8f2008-11-25 15:18:29 +01004594 case STAC_DELL_M6_DMIC: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004595 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4596 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004597 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004598 break;
Takashi Iwai661cd8f2008-11-25 15:18:29 +01004599 case STAC_DELL_M6_BOTH: /* Both */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004600 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4601 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4602 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004603 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004604 break;
4605 }
4606 break;
4607 default:
4608 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004609 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05004610 spec->eapd_switch = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004611 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004612 if (spec->board_config > STAC_92HD73XX_REF) {
4613 /* GPIO0 High = Enable EAPD */
4614 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
4615 spec->gpio_data = 0x01;
4616 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004617 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004618
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004619 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
4620 spec->pwr_nids = stac92hd73xx_pwr_nids;
4621
Matthew Ranostayd9737752008-09-07 12:03:41 +02004622 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004623
4624 if (!err) {
4625 if (spec->board_config < 0) {
4626 printk(KERN_WARNING "hda_codec: No auto-config is "
4627 "available, default to model=ref\n");
4628 spec->board_config = STAC_92HD73XX_REF;
4629 goto again;
4630 }
4631 err = -EINVAL;
4632 }
4633
4634 if (err < 0) {
4635 stac92xx_free(codec);
4636 return err;
4637 }
4638
Takashi Iwai9e43f0d2008-12-17 14:51:01 +01004639 if (spec->board_config == STAC_92HD73XX_NO_JD)
4640 spec->hp_detect = 0;
4641
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004642 codec->patch_ops = stac92xx_patch_ops;
4643
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01004644 codec->proc_widget_hook = stac92hd7x_proc_hook;
4645
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004646 return 0;
4647}
4648
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004649static struct hda_input_mux stac92hd83xxx_dmux = {
4650 .num_items = 3,
4651 .items = {
4652 { "Analog Inputs", 0x03 },
4653 { "Digital Mic 1", 0x04 },
4654 { "Digital Mic 2", 0x05 },
4655 }
4656};
4657
4658static int patch_stac92hd83xxx(struct hda_codec *codec)
4659{
4660 struct sigmatel_spec *spec;
4661 int err;
4662
4663 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4664 if (spec == NULL)
4665 return -ENOMEM;
4666
4667 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004668 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004669 spec->mono_nid = 0x19;
4670 spec->digbeep_nid = 0x21;
4671 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4672 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4673 spec->adc_nids = stac92hd83xxx_adc_nids;
4674 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4675 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4676 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004677 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004678
4679 spec->init = stac92hd83xxx_core_init;
4680 switch (codec->vendor_id) {
4681 case 0x111d7605:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004682 break;
4683 default:
4684 spec->num_pwrs--;
4685 spec->init++; /* switch to config #2 */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004686 }
4687
4688 spec->mixer = stac92hd83xxx_mixer;
4689 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4690 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4691 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4692 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4693 spec->dinput_mux = &stac92hd83xxx_dmux;
4694 spec->pin_nids = stac92hd83xxx_pin_nids;
4695 spec->board_config = snd_hda_check_board_config(codec,
4696 STAC_92HD83XXX_MODELS,
4697 stac92hd83xxx_models,
4698 stac92hd83xxx_cfg_tbl);
4699again:
4700 if (spec->board_config < 0) {
4701 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4702 " STAC92HD83XXX, using BIOS defaults\n");
4703 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004704 } else
4705 err = stac_save_pin_cfgs(codec,
4706 stac92hd83xxx_brd_tbl[spec->board_config]);
4707 if (err < 0) {
4708 stac92xx_free(codec);
4709 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004710 }
4711
4712 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4713 if (!err) {
4714 if (spec->board_config < 0) {
4715 printk(KERN_WARNING "hda_codec: No auto-config is "
4716 "available, default to model=ref\n");
4717 spec->board_config = STAC_92HD83XXX_REF;
4718 goto again;
4719 }
4720 err = -EINVAL;
4721 }
4722
4723 if (err < 0) {
4724 stac92xx_free(codec);
4725 return err;
4726 }
4727
4728 codec->patch_ops = stac92xx_patch_ops;
4729
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01004730 codec->proc_widget_hook = stac92hd_proc_hook;
4731
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004732 return 0;
4733}
4734
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004735static struct hda_input_mux stac92hd71bxx_dmux = {
4736 .num_items = 4,
4737 .items = {
4738 { "Analog Inputs", 0x00 },
4739 { "Mixer", 0x01 },
4740 { "Digital Mic 1", 0x02 },
4741 { "Digital Mic 2", 0x03 },
4742 }
4743};
4744
Matthew Ranostaye035b842007-11-06 11:53:55 +01004745static int patch_stac92hd71bxx(struct hda_codec *codec)
4746{
4747 struct sigmatel_spec *spec;
4748 int err = 0;
4749
4750 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4751 if (spec == NULL)
4752 return -ENOMEM;
4753
4754 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004755 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004756 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004757 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004758 spec->pin_nids = stac92hd71bxx_pin_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004759 memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
4760 sizeof(stac92hd71bxx_dmux));
Matthew Ranostaye035b842007-11-06 11:53:55 +01004761 spec->board_config = snd_hda_check_board_config(codec,
4762 STAC_92HD71BXX_MODELS,
4763 stac92hd71bxx_models,
4764 stac92hd71bxx_cfg_tbl);
4765again:
4766 if (spec->board_config < 0) {
4767 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4768 " STAC92HD71BXX, using BIOS defaults\n");
4769 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004770 } else
4771 err = stac_save_pin_cfgs(codec,
4772 stac92hd71bxx_brd_tbl[spec->board_config]);
4773 if (err < 0) {
4774 stac92xx_free(codec);
4775 return err;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004776 }
4777
Takashi Iwai41c3b642008-11-18 10:45:15 +01004778 if (spec->board_config > STAC_92HD71BXX_REF) {
4779 /* GPIO0 = EAPD */
4780 spec->gpio_mask = 0x01;
4781 spec->gpio_dir = 0x01;
4782 spec->gpio_data = 0x01;
4783 }
4784
Matthew Ranostay541eee82007-12-14 12:08:04 +01004785 switch (codec->vendor_id) {
4786 case 0x111d76b6: /* 4 Port without Analog Mixer */
4787 case 0x111d76b7:
4788 case 0x111d76b4: /* 6 Port without Analog Mixer */
4789 case 0x111d76b5:
4790 spec->mixer = stac92hd71bxx_mixer;
4791 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004792 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004793 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004794 case 0x111d7608: /* 5 Port with Analog Mixer */
Takashi Iwai8e5f2622008-11-15 19:28:54 +01004795 switch (spec->board_config) {
4796 case STAC_HP_M4:
Matthew Ranostay72474be2008-10-09 09:32:17 -04004797 /* Enable VREF power saving on GPIO1 detect */
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004798 err = stac_add_event(spec, codec->afg,
4799 STAC_VREF_EVENT, 0x02);
4800 if (err < 0)
4801 return err;
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01004802 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay72474be2008-10-09 09:32:17 -04004803 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4804 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004805 AC_VERB_SET_UNSOLICITED_ENABLE,
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004806 AC_USRSP_EN | err);
Matthew Ranostay72474be2008-10-09 09:32:17 -04004807 spec->gpio_mask |= 0x02;
4808 break;
4809 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004810 if ((codec->revision_id & 0xf) == 0 ||
Takashi Iwai8c2f7672008-12-01 11:54:35 +01004811 (codec->revision_id & 0xf) == 1)
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004812 spec->stream_delay = 40; /* 40 milliseconds */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004813
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004814 /* no output amps */
4815 spec->num_pwrs = 0;
4816 spec->mixer = stac92hd71bxx_analog_mixer;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004817 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004818
4819 /* disable VSW */
4820 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004821 stac_change_pin_config(codec, 0xf, 0x40f000f0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004822 break;
4823 case 0x111d7603: /* 6 Port with Analog Mixer */
Takashi Iwai8c2f7672008-12-01 11:54:35 +01004824 if ((codec->revision_id & 0xf) == 1)
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004825 spec->stream_delay = 40; /* 40 milliseconds */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004826
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004827 /* no output amps */
4828 spec->num_pwrs = 0;
4829 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004830 default:
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004831 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004832 spec->mixer = stac92hd71bxx_analog_mixer;
4833 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004834 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004835 }
4836
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004837 spec->aloopback_mask = 0x50;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004838 spec->aloopback_shift = 0;
4839
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004840 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004841 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004842 spec->mux_nids = stac92hd71bxx_mux_nids;
4843 spec->adc_nids = stac92hd71bxx_adc_nids;
4844 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004845 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004846 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004847 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004848
4849 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4850 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004851
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004852 switch (spec->board_config) {
4853 case STAC_HP_M4:
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004854 /* enable internal microphone */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004855 stac_change_pin_config(codec, 0x0e, 0x01813040);
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004856 stac92xx_auto_set_pinctl(codec, 0x0e,
4857 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05004858 /* fallthru */
4859 case STAC_DELL_M4_2:
4860 spec->num_dmics = 0;
4861 spec->num_smuxes = 0;
4862 spec->num_dmuxes = 0;
4863 break;
4864 case STAC_DELL_M4_1:
4865 case STAC_DELL_M4_3:
4866 spec->num_dmics = 1;
4867 spec->num_smuxes = 0;
4868 spec->num_dmuxes = 0;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004869 break;
4870 default:
4871 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4872 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4873 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4874 };
4875
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004876 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004877 if (spec->dinput_mux)
4878 spec->private_dimux.num_items +=
4879 spec->num_dmics -
4880 (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004881
4882 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4883 if (!err) {
4884 if (spec->board_config < 0) {
4885 printk(KERN_WARNING "hda_codec: No auto-config is "
4886 "available, default to model=ref\n");
4887 spec->board_config = STAC_92HD71BXX_REF;
4888 goto again;
4889 }
4890 err = -EINVAL;
4891 }
4892
4893 if (err < 0) {
4894 stac92xx_free(codec);
4895 return err;
4896 }
4897
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01004898 codec->proc_widget_hook = stac92hd7x_proc_hook;
4899
Matthew Ranostaye035b842007-11-06 11:53:55 +01004900 return 0;
4901};
4902
Matt2f2f4252005-04-13 14:45:30 +02004903static int patch_stac922x(struct hda_codec *codec)
4904{
4905 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004906 int err;
Matt2f2f4252005-04-13 14:45:30 +02004907
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004908 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004909 if (spec == NULL)
4910 return -ENOMEM;
4911
4912 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004913 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004914 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004915 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4916 stac922x_models,
4917 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004918 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004919 spec->gpio_mask = spec->gpio_dir = 0x03;
4920 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004921 /* Intel Macs have all same PCI SSID, so we need to check
4922 * codec SSID to distinguish the exact models
4923 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004924 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004925 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004926
4927 case 0x106b0800:
4928 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004929 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004930 case 0x106b0600:
4931 case 0x106b0700:
4932 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004933 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004934 case 0x106b0e00:
4935 case 0x106b0f00:
4936 case 0x106b1600:
4937 case 0x106b1700:
4938 case 0x106b0200:
4939 case 0x106b1e00:
4940 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004941 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004942 case 0x106b1a00:
4943 case 0x00000100:
4944 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004945 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004946 case 0x106b0a00:
4947 case 0x106b2200:
4948 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004949 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004950 default:
4951 spec->board_config = STAC_INTEL_MAC_V3;
4952 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004953 }
4954 }
4955
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004956 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004957 if (spec->board_config < 0) {
4958 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4959 "using BIOS defaults\n");
4960 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01004961 } else
4962 err = stac_save_pin_cfgs(codec,
4963 stac922x_brd_tbl[spec->board_config]);
4964 if (err < 0) {
4965 stac92xx_free(codec);
4966 return err;
Matt Porter403d1942005-11-29 15:00:51 +01004967 }
Matt2f2f4252005-04-13 14:45:30 +02004968
Matt2f2f4252005-04-13 14:45:30 +02004969 spec->adc_nids = stac922x_adc_nids;
4970 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004971 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004972 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004973 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004974 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004975
4976 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004977 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004978
4979 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004980
Matt Porter3cc08dc2006-01-23 15:27:49 +01004981 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004982 if (!err) {
4983 if (spec->board_config < 0) {
4984 printk(KERN_WARNING "hda_codec: No auto-config is "
4985 "available, default to model=ref\n");
4986 spec->board_config = STAC_D945_REF;
4987 goto again;
4988 }
4989 err = -EINVAL;
4990 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004991 if (err < 0) {
4992 stac92xx_free(codec);
4993 return err;
4994 }
4995
4996 codec->patch_ops = stac92xx_patch_ops;
4997
Takashi Iwai807a46362007-05-29 19:01:37 +02004998 /* Fix Mux capture level; max to 2 */
4999 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
5000 (0 << AC_AMPCAP_OFFSET_SHIFT) |
5001 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
5002 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
5003 (0 << AC_AMPCAP_MUTE_SHIFT));
5004
Matt Porter3cc08dc2006-01-23 15:27:49 +01005005 return 0;
5006}
5007
5008static int patch_stac927x(struct hda_codec *codec)
5009{
5010 struct sigmatel_spec *spec;
5011 int err;
5012
5013 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5014 if (spec == NULL)
5015 return -ENOMEM;
5016
5017 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02005018 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02005019 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005020 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
5021 stac927x_models,
5022 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005023 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005024 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
5025 if (spec->board_config < 0)
5026 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
5027 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02005028 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005029 } else
5030 err = stac_save_pin_cfgs(codec,
5031 stac927x_brd_tbl[spec->board_config]);
5032 if (err < 0) {
5033 stac92xx_free(codec);
5034 return err;
Matt Porter3cc08dc2006-01-23 15:27:49 +01005035 }
5036
Matthew Ranostay1cd22242008-07-18 18:20:52 +02005037 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005038 spec->adc_nids = stac927x_adc_nids;
5039 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
5040 spec->mux_nids = stac927x_mux_nids;
5041 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02005042 spec->smux_nids = stac927x_smux_nids;
5043 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04005044 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01005045 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005046 spec->multiout.dac_nids = spec->dac_nids;
5047
Tobin Davis81d3dbd2006-08-22 19:44:45 +02005048 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02005049 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005050 case STAC_D965_5ST:
5051 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005052 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005053 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005054 spec->num_dmics = 0;
5055
Tobin Davis93ed1502006-09-01 21:03:12 +02005056 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005057 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02005058 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005059 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02005060 switch (codec->subsystem_id) {
5061 case 0x10280209:
5062 case 0x1028022e:
5063 /* correct the device field to SPDIF out */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005064 stac_change_pin_config(codec, 0x21, 0x01442070);
Matthew Ranostay780c8be2008-04-14 13:32:27 +02005065 break;
5066 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01005067 /* configure the analog microphone on some laptops */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005068 stac_change_pin_config(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01005069 /* correct the front output jack as a hp out */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005070 stac_change_pin_config(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01005071 /* correct the front input jack as a mic */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005072 stac_change_pin_config(codec, 0x0e, 0x02a79130);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01005073 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005074 case STAC_DELL_3ST:
5075 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005076 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005077 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005078 spec->dmic_nids = stac927x_dmic_nids;
5079 spec->num_dmics = STAC927X_NUM_DMICS;
5080
Tobin Davis93ed1502006-09-01 21:03:12 +02005081 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005082 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005083 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01005084 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02005085 break;
5086 default:
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04005087 if (spec->board_config > STAC_D965_REF) {
5088 /* GPIO0 High = Enable EAPD */
5089 spec->eapd_mask = spec->gpio_mask = 0x01;
5090 spec->gpio_dir = spec->gpio_data = 0x01;
5091 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005092 spec->num_dmics = 0;
5093
Tobin Davis81d3dbd2006-08-22 19:44:45 +02005094 spec->init = stac927x_core_init;
5095 spec->mixer = stac927x_mixer;
5096 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01005097
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005098 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005099 spec->aloopback_mask = 0x40;
5100 spec->aloopback_shift = 0;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05005101 spec->eapd_switch = 1;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01005102
Matt Porter3cc08dc2006-01-23 15:27:49 +01005103 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005104 if (!err) {
5105 if (spec->board_config < 0) {
5106 printk(KERN_WARNING "hda_codec: No auto-config is "
5107 "available, default to model=ref\n");
5108 spec->board_config = STAC_D965_REF;
5109 goto again;
5110 }
5111 err = -EINVAL;
5112 }
Mattc7d4b2f2005-06-27 14:59:41 +02005113 if (err < 0) {
5114 stac92xx_free(codec);
5115 return err;
5116 }
Matt2f2f4252005-04-13 14:45:30 +02005117
5118 codec->patch_ops = stac92xx_patch_ops;
5119
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01005120 codec->proc_widget_hook = stac927x_proc_hook;
5121
Takashi Iwai52987652008-01-16 16:09:47 +01005122 /*
5123 * !!FIXME!!
5124 * The STAC927x seem to require fairly long delays for certain
5125 * command sequences. With too short delays (even if the answer
5126 * is set to RIRB properly), it results in the silence output
5127 * on some hardwares like Dell.
5128 *
5129 * The below flag enables the longer delay (see get_response
5130 * in hda_intel.c).
5131 */
5132 codec->bus->needs_damn_long_delay = 1;
5133
Takashi Iwaie28d8322008-12-17 13:48:29 +01005134 /* no jack detecion for ref-no-jd model */
5135 if (spec->board_config == STAC_D965_REF_NO_JD)
5136 spec->hp_detect = 0;
5137
Matt2f2f4252005-04-13 14:45:30 +02005138 return 0;
5139}
5140
Matt Porterf3302a52006-07-31 12:49:34 +02005141static int patch_stac9205(struct hda_codec *codec)
5142{
5143 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02005144 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02005145
5146 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5147 if (spec == NULL)
5148 return -ENOMEM;
5149
5150 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02005151 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02005152 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005153 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
5154 stac9205_models,
5155 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005156 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02005157 if (spec->board_config < 0) {
5158 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
5159 err = stac92xx_save_bios_config_regs(codec);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005160 } else
5161 err = stac_save_pin_cfgs(codec,
5162 stac9205_brd_tbl[spec->board_config]);
5163 if (err < 0) {
5164 stac92xx_free(codec);
5165 return err;
Matt Porterf3302a52006-07-31 12:49:34 +02005166 }
5167
Matthew Ranostay1cd22242008-07-18 18:20:52 +02005168 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02005169 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005170 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02005171 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01005172 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02005173 spec->smux_nids = stac9205_smux_nids;
5174 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02005175 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02005176 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005177 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01005178 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005179 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02005180
5181 spec->init = stac9205_core_init;
5182 spec->mixer = stac9205_mixer;
5183
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005184 spec->aloopback_mask = 0x40;
5185 spec->aloopback_shift = 0;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05005186 spec->eapd_switch = 1;
Matt Porterf3302a52006-07-31 12:49:34 +02005187 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02005188
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005189 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005190 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02005191 /* Enable SPDIF in/out */
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005192 stac_change_pin_config(codec, 0x1f, 0x01441030);
5193 stac_change_pin_config(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01005194
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005195 /* Enable unsol response for GPIO4/Dock HP connection */
Takashi Iwaic6e4c662008-11-25 11:58:19 +01005196 err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
5197 if (err < 0)
5198 return err;
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01005199 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005200 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
5201 snd_hda_codec_write_cache(codec, codec->afg, 0,
Takashi Iwaic6e4c662008-11-25 11:58:19 +01005202 AC_VERB_SET_UNSOLICITED_ENABLE,
5203 AC_USRSP_EN | err);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005204
5205 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005206 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005207 spec->gpio_mask = 0x1b;
5208 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01005209 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005210 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02005211 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005212 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005213 break;
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04005214 case STAC_9205_REF:
5215 /* SPDIF-In enabled */
5216 break;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005217 default:
5218 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005219 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005220 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005221 break;
5222 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02005223
Matt Porterf3302a52006-07-31 12:49:34 +02005224 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005225 if (!err) {
5226 if (spec->board_config < 0) {
5227 printk(KERN_WARNING "hda_codec: No auto-config is "
5228 "available, default to model=ref\n");
5229 spec->board_config = STAC_9205_REF;
5230 goto again;
5231 }
5232 err = -EINVAL;
5233 }
Matt Porterf3302a52006-07-31 12:49:34 +02005234 if (err < 0) {
5235 stac92xx_free(codec);
5236 return err;
5237 }
5238
5239 codec->patch_ops = stac92xx_patch_ops;
5240
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01005241 codec->proc_widget_hook = stac9205_proc_hook;
5242
Matt Porterf3302a52006-07-31 12:49:34 +02005243 return 0;
5244}
5245
Matt2f2f4252005-04-13 14:45:30 +02005246/*
Guillaume Munch6d859062006-08-22 17:15:47 +02005247 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01005248 */
5249
Guillaume Munch99ccc562006-08-16 19:35:12 +02005250/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005251static hda_nid_t vaio_dacs[] = { 0x2 };
5252#define VAIO_HP_DAC 0x5
5253static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
5254static hda_nid_t vaio_mux_nids[] = { 0x15 };
5255
5256static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02005257 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01005258 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02005259 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005260 { "Mic Jack", 0x1 },
5261 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01005262 { "PCM", 0x3 },
5263 }
5264};
5265
5266static struct hda_verb vaio_init[] = {
5267 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005268 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01005269 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5270 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5271 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5272 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005273 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005274 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5275 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5276 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5278 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5279 {}
5280};
5281
Guillaume Munch6d859062006-08-22 17:15:47 +02005282static struct hda_verb vaio_ar_init[] = {
5283 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
5284 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5285 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5286 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5287/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
5288 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005289 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02005290 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5291 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5292/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
5293 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5294 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5295 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5296 {}
5297};
5298
Takashi Iwaidb064e52006-03-16 16:04:58 +01005299static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwai127e82e2008-11-14 14:03:33 +01005300 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
5301 HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
5302 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
5303 HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005304 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5305 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5306 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5307 {
5308 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5309 .name = "Capture Source",
5310 .count = 1,
5311 .info = stac92xx_mux_enum_info,
5312 .get = stac92xx_mux_enum_get,
5313 .put = stac92xx_mux_enum_put,
5314 },
5315 {}
5316};
5317
Guillaume Munch6d859062006-08-22 17:15:47 +02005318static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwai127e82e2008-11-14 14:03:33 +01005319 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
5320 HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
5321 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
5322 HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
Guillaume Munch6d859062006-08-22 17:15:47 +02005323 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5324 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5325 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5326 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
5327 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
5328 {
5329 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5330 .name = "Capture Source",
5331 .count = 1,
5332 .info = stac92xx_mux_enum_info,
5333 .get = stac92xx_mux_enum_get,
5334 .put = stac92xx_mux_enum_put,
5335 },
5336 {}
5337};
5338
5339static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01005340 .build_controls = stac92xx_build_controls,
5341 .build_pcms = stac92xx_build_pcms,
5342 .init = stac92xx_init,
5343 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005344#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01005345 .resume = stac92xx_resume,
5346#endif
5347};
5348
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005349static int stac9872_vaio_init(struct hda_codec *codec)
5350{
5351 int err;
5352
5353 err = stac92xx_init(codec);
5354 if (err < 0)
5355 return err;
5356 if (codec->patch_ops.unsol_event)
5357 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
5358 return 0;
5359}
5360
5361static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
5362{
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01005363 if (get_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005364 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5365 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5366 } else {
5367 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5368 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5369 }
5370}
5371
5372static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
5373{
5374 switch (res >> 26) {
5375 case STAC_HP_EVENT:
5376 stac9872_vaio_hp_detect(codec, res);
5377 break;
5378 }
5379}
5380
5381static struct hda_codec_ops stac9872_vaio_patch_ops = {
5382 .build_controls = stac92xx_build_controls,
5383 .build_pcms = stac92xx_build_pcms,
5384 .init = stac9872_vaio_init,
5385 .free = stac92xx_free,
5386 .unsol_event = stac9872_vaio_unsol_event,
5387#ifdef CONFIG_PM
5388 .resume = stac92xx_resume,
5389#endif
5390};
5391
Guillaume Munch6d859062006-08-22 17:15:47 +02005392enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
5393 CXD9872RD_VAIO,
5394 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
5395 STAC9872AK_VAIO,
5396 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
5397 STAC9872K_VAIO,
5398 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005399 CXD9872AKD_VAIO,
5400 STAC_9872_MODELS,
5401};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005402
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005403static const char *stac9872_models[STAC_9872_MODELS] = {
5404 [CXD9872RD_VAIO] = "vaio",
5405 [CXD9872AKD_VAIO] = "vaio-ar",
5406};
5407
5408static struct snd_pci_quirk stac9872_cfg_tbl[] = {
5409 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
5410 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
5411 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01005412 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005413 {}
5414};
5415
Guillaume Munch6d859062006-08-22 17:15:47 +02005416static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01005417{
5418 struct sigmatel_spec *spec;
5419 int board_config;
5420
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005421 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
5422 stac9872_models,
5423 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01005424 if (board_config < 0)
5425 /* unknown config, let generic-parser do its job... */
5426 return snd_hda_parse_generic_codec(codec);
5427
5428 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5429 if (spec == NULL)
5430 return -ENOMEM;
5431
5432 codec->spec = spec;
5433 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02005434 case CXD9872RD_VAIO:
5435 case STAC9872AK_VAIO:
5436 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01005437 spec->mixer = vaio_mixer;
5438 spec->init = vaio_init;
5439 spec->multiout.max_channels = 2;
5440 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5441 spec->multiout.dac_nids = vaio_dacs;
5442 spec->multiout.hp_nid = VAIO_HP_DAC;
5443 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
5444 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005445 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005446 spec->input_mux = &vaio_mux;
5447 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005448 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005449 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02005450
5451 case CXD9872AKD_VAIO:
5452 spec->mixer = vaio_ar_mixer;
5453 spec->init = vaio_ar_init;
5454 spec->multiout.max_channels = 2;
5455 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5456 spec->multiout.dac_nids = vaio_dacs;
5457 spec->multiout.hp_nid = VAIO_HP_DAC;
5458 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005459 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02005460 spec->adc_nids = vaio_adcs;
5461 spec->input_mux = &vaio_mux;
5462 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005463 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02005464 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005465 }
5466
Takashi Iwaidb064e52006-03-16 16:04:58 +01005467 return 0;
5468}
5469
5470
5471/*
Matt2f2f4252005-04-13 14:45:30 +02005472 * patch entries
5473 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005474static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
Matt2f2f4252005-04-13 14:45:30 +02005475 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
5476 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
5477 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
5478 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
5479 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
5480 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
5481 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02005482 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
5483 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
5484 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
5485 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
5486 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
5487 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01005488 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
5489 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
5490 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
5491 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
5492 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
5493 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
5494 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
5495 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
5496 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
5497 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01005498 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
5499 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
5500 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
5501 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
5502 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
5503 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02005504 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
5505 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02005506 /* The following does not take into account .id=0x83847661 when subsys =
5507 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
5508 * currently not fully supported.
5509 */
5510 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
5511 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
5512 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02005513 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
5514 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
5515 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
5516 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
5517 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
5518 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
5519 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
5520 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005521 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005522 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
5523 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005524 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01005525 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
5526 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005527 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01005528 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5529 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5530 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5531 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5532 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5533 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5534 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
5535 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02005536 {} /* terminator */
5537};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005538
5539MODULE_ALIAS("snd-hda-codec-id:8384*");
5540MODULE_ALIAS("snd-hda-codec-id:111d*");
5541
5542MODULE_LICENSE("GPL");
5543MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
5544
5545static struct hda_codec_preset_list sigmatel_list = {
5546 .preset = snd_hda_preset_sigmatel,
5547 .owner = THIS_MODULE,
5548};
5549
5550static int __init patch_sigmatel_init(void)
5551{
5552 return snd_hda_add_codec_preset(&sigmatel_list);
5553}
5554
5555static void __exit patch_sigmatel_exit(void)
5556{
5557 snd_hda_delete_codec_preset(&sigmatel_list);
5558}
5559
5560module_init(patch_sigmatel_init)
5561module_exit(patch_sigmatel_exit)