blob: 9563b5bbb272f41dda83997ceaf97bba7484af22 [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010035#include "hda_patch.h"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020036#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020037
Matt4e550962005-07-04 17:51:39 +020038#define NUM_CONTROL_ALLOC 32
Matthew Ranostayc39555d2008-11-14 17:46:22 -050039
40#define STAC_VREF_EVENT 0x00
41#define STAC_INSERT_EVENT 0x10
Matthew Ranostaya64135a2008-01-10 16:55:06 +010042#define STAC_PWR_EVENT 0x20
43#define STAC_HP_EVENT 0x30
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 {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010072 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010073 STAC_DELL_M6,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -050074 STAC_DELL_EQ,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010075 STAC_92HD73XX_MODELS
76};
77
78enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020079 STAC_92HD83XXX_REF,
80 STAC_92HD83XXX_MODELS
81};
82
83enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010084 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010085 STAC_DELL_M4_1,
86 STAC_DELL_M4_2,
Matthew Ranostay6a14f582008-09-12 12:02:30 -040087 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010088 STAC_92HD71BXX_MODELS
89};
90
91enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010092 STAC_925x_REF,
93 STAC_M2_2,
94 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020095 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010096 STAC_925x_MODELS
97};
98
99enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100100 STAC_D945_REF,
101 STAC_D945GTP3,
102 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200103 STAC_INTEL_MAC_V1,
104 STAC_INTEL_MAC_V2,
105 STAC_INTEL_MAC_V3,
106 STAC_INTEL_MAC_V4,
107 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800108 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
109 * is given, one of the above models will be
110 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200111 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100112 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100113 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100114 STAC_MACBOOK_PRO_V1,
115 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200116 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200117 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300118 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200119 STAC_922X_DELL_D81,
120 STAC_922X_DELL_D82,
121 STAC_922X_DELL_M81,
122 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100123 STAC_922X_MODELS
124};
125
126enum {
127 STAC_D965_REF,
128 STAC_D965_3ST,
129 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200130 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100131 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100132 STAC_927X_MODELS
133};
Matt Porter403d1942005-11-29 15:00:51 +0100134
Matt2f2f4252005-04-13 14:45:30 +0200135struct sigmatel_spec {
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100136 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200137 unsigned int num_mixers;
138
Matt Porter403d1942005-11-29 15:00:51 +0100139 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200140 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100141 unsigned int line_switch: 1;
142 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100143 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100144 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400145 unsigned int spdif_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200146
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100147 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200148 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100149 unsigned int gpio_mask;
150 unsigned int gpio_dir;
151 unsigned int gpio_data;
152 unsigned int gpio_mute;
153
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200154 /* stream */
155 unsigned int stream_delay;
156
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100157 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100158 unsigned char aloopback_mask;
159 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200160
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100161 /* power management */
162 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200163 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100164 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100165 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100166
Matt2f2f4252005-04-13 14:45:30 +0200167 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100168 struct hda_input_mux *mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400169 struct hda_input_mux *amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100170 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200171 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100172 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200173
174 /* capture */
175 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200176 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200177 hda_nid_t *mux_nids;
178 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200179 hda_nid_t *dmic_nids;
180 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100181 hda_nid_t *dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +0100182 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200183 hda_nid_t *smux_nids;
184 unsigned int num_smuxes;
Matthew Ranostay65973632008-09-16 10:39:37 -0400185 const char **spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200186
Mattdabbed62005-06-14 10:19:34 +0200187 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100188 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200189 hda_nid_t anabeep_nid;
190 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200191
Matt2f2f4252005-04-13 14:45:30 +0200192 /* pin widgets */
193 hda_nid_t *pin_nids;
194 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200195 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200196 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200197
198 /* codec specific stuff */
199 struct hda_verb *init;
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100200 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200201
202 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200203 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100204 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200205 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100206 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200207 struct hda_input_mux *sinput_mux;
208 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400209 unsigned int cur_amux;
210 hda_nid_t *amp_nids;
211 unsigned int num_amps;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200212 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200213
Matt Porter403d1942005-11-29 15:00:51 +0100214 /* i/o switches */
215 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200216 unsigned int clfe_swap;
Takashi Iwaid7a89432008-11-12 09:48:04 +0100217 unsigned int hp_switch; /* NID of HP as line-out */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200218 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200219
Mattc7d4b2f2005-06-27 14:59:41 +0200220 struct hda_pcm pcm_rec[2]; /* PCM information */
221
222 /* dynamic controls and input_mux */
223 struct auto_pin_cfg autocfg;
224 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100225 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200226 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200227 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200228 struct hda_input_mux private_smux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400229 struct hda_input_mux private_amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100230 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200231};
232
233static hda_nid_t stac9200_adc_nids[1] = {
234 0x03,
235};
236
237static hda_nid_t stac9200_mux_nids[1] = {
238 0x0c,
239};
240
241static hda_nid_t stac9200_dac_nids[1] = {
242 0x02,
243};
244
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100245static hda_nid_t stac92hd73xx_pwr_nids[8] = {
246 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
247 0x0f, 0x10, 0x11
248};
249
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400250static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
251 0x26, 0,
252};
253
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100254static hda_nid_t stac92hd73xx_adc_nids[2] = {
255 0x1a, 0x1b
256};
257
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400258#define DELL_M6_AMP 2
259static hda_nid_t stac92hd73xx_amp_nids[3] = {
260 0x0b, 0x0c, 0x0e
Matthew Ranostay89385032008-09-11 09:49:39 -0400261};
262
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100263#define STAC92HD73XX_NUM_DMICS 2
264static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
265 0x13, 0x14, 0
266};
267
268#define STAC92HD73_DAC_COUNT 5
269static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
270 0x15, 0x16, 0x17, 0x18, 0x19,
271};
272
273static hda_nid_t stac92hd73xx_mux_nids[4] = {
274 0x28, 0x29, 0x2a, 0x2b,
275};
276
277static hda_nid_t stac92hd73xx_dmux_nids[2] = {
278 0x20, 0x21,
279};
280
Matthew Ranostayd9737752008-09-07 12:03:41 +0200281static hda_nid_t stac92hd73xx_smux_nids[2] = {
282 0x22, 0x23,
283};
284
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200285#define STAC92HD83XXX_NUM_DMICS 2
286static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
287 0x11, 0x12, 0
288};
289
290#define STAC92HD81_DAC_COUNT 2
291#define STAC92HD83_DAC_COUNT 3
292static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
293 0x13, 0x14, 0x22,
294};
295
296static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
297 0x17, 0x18,
298};
299
300static hda_nid_t stac92hd83xxx_adc_nids[2] = {
301 0x15, 0x16,
302};
303
304static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
305 0xa, 0xb, 0xd, 0xe,
306};
307
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400308static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
309 0x1e, 0,
310};
311
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200312static unsigned int stac92hd83xxx_pwr_mapping[4] = {
313 0x03, 0x0c, 0x10, 0x40,
314};
315
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100316static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
317 0x0a, 0x0d, 0x0f
318};
319
Matthew Ranostaye035b842007-11-06 11:53:55 +0100320static hda_nid_t stac92hd71bxx_adc_nids[2] = {
321 0x12, 0x13,
322};
323
324static hda_nid_t stac92hd71bxx_mux_nids[2] = {
325 0x1a, 0x1b
326};
327
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400328static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
329 0x1c, 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100330};
331
Matthew Ranostayd9737752008-09-07 12:03:41 +0200332static hda_nid_t stac92hd71bxx_smux_nids[2] = {
333 0x24, 0x25,
334};
335
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100336static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100337 0x10, /*0x11, */
338};
339
340#define STAC92HD71BXX_NUM_DMICS 2
341static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
342 0x18, 0x19, 0
343};
344
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400345static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
346 0x22, 0
347};
348
Tobin Davis8e21c342007-01-08 11:04:17 +0100349static hda_nid_t stac925x_adc_nids[1] = {
350 0x03,
351};
352
353static hda_nid_t stac925x_mux_nids[1] = {
354 0x0f,
355};
356
357static hda_nid_t stac925x_dac_nids[1] = {
358 0x02,
359};
360
Takashi Iwaif6e98522007-10-16 14:27:04 +0200361#define STAC925X_NUM_DMICS 1
362static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
363 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200364};
365
Takashi Iwai16970552007-12-18 18:05:52 +0100366static hda_nid_t stac925x_dmux_nids[1] = {
367 0x14,
368};
369
Matt2f2f4252005-04-13 14:45:30 +0200370static hda_nid_t stac922x_adc_nids[2] = {
371 0x06, 0x07,
372};
373
374static hda_nid_t stac922x_mux_nids[2] = {
375 0x12, 0x13,
376};
377
Matt Porter3cc08dc2006-01-23 15:27:49 +0100378static hda_nid_t stac927x_adc_nids[3] = {
379 0x07, 0x08, 0x09
380};
381
382static hda_nid_t stac927x_mux_nids[3] = {
383 0x15, 0x16, 0x17
384};
385
Matthew Ranostayd9737752008-09-07 12:03:41 +0200386static hda_nid_t stac927x_smux_nids[1] = {
387 0x21,
388};
389
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100390static hda_nid_t stac927x_dac_nids[6] = {
391 0x02, 0x03, 0x04, 0x05, 0x06, 0
392};
393
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100394static hda_nid_t stac927x_dmux_nids[1] = {
395 0x1b,
396};
397
Matthew Ranostay7f168592007-10-18 17:38:17 +0200398#define STAC927X_NUM_DMICS 2
399static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
400 0x13, 0x14, 0
401};
402
Matthew Ranostay65973632008-09-16 10:39:37 -0400403static const char *stac927x_spdif_labels[5] = {
404 "Digital Playback", "ADAT", "Analog Mux 1",
405 "Analog Mux 2", "Analog Mux 3"
406};
407
Matt Porterf3302a52006-07-31 12:49:34 +0200408static hda_nid_t stac9205_adc_nids[2] = {
409 0x12, 0x13
410};
411
412static hda_nid_t stac9205_mux_nids[2] = {
413 0x19, 0x1a
414};
415
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100416static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai16970552007-12-18 18:05:52 +0100417 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100418};
419
Matthew Ranostayd9737752008-09-07 12:03:41 +0200420static hda_nid_t stac9205_smux_nids[1] = {
421 0x21,
422};
423
Takashi Iwaif6e98522007-10-16 14:27:04 +0200424#define STAC9205_NUM_DMICS 2
425static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
426 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200427};
428
Mattc7d4b2f2005-06-27 14:59:41 +0200429static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200430 0x08, 0x09, 0x0d, 0x0e,
431 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200432};
433
Tobin Davis8e21c342007-01-08 11:04:17 +0100434static hda_nid_t stac925x_pin_nids[8] = {
435 0x07, 0x08, 0x0a, 0x0b,
436 0x0c, 0x0d, 0x10, 0x11,
437};
438
Matt2f2f4252005-04-13 14:45:30 +0200439static hda_nid_t stac922x_pin_nids[10] = {
440 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
441 0x0f, 0x10, 0x11, 0x15, 0x1b,
442};
443
Matthew Ranostaya7662642008-02-21 07:51:14 +0100444static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100445 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
446 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200447 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100448};
449
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200450static hda_nid_t stac92hd83xxx_pin_nids[14] = {
451 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
452 0x0f, 0x10, 0x11, 0x12, 0x13,
453 0x1d, 0x1e, 0x1f, 0x20
454};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400455static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100456 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
457 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400458 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100459};
460
Matt Porter3cc08dc2006-01-23 15:27:49 +0100461static hda_nid_t stac927x_pin_nids[14] = {
462 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
463 0x0f, 0x10, 0x11, 0x12, 0x13,
464 0x14, 0x21, 0x22, 0x23,
465};
466
Matt Porterf3302a52006-07-31 12:49:34 +0200467static hda_nid_t stac9205_pin_nids[12] = {
468 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
469 0x0f, 0x14, 0x16, 0x17, 0x18,
470 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200471};
472
Matthew Ranostay89385032008-09-11 09:49:39 -0400473#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
474
475static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
476 struct snd_ctl_elem_value *ucontrol)
477{
478 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
479 struct sigmatel_spec *spec = codec->spec;
480 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
481
482 kcontrol->private_value ^= get_amp_nid(kcontrol);
483 kcontrol->private_value |= nid;
484
485 return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
486}
487
488static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
489 struct snd_ctl_elem_value *ucontrol)
490{
491 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
492 struct sigmatel_spec *spec = codec->spec;
493 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
494
495 kcontrol->private_value ^= get_amp_nid(kcontrol);
496 kcontrol->private_value |= nid;
497
498 return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
499}
500
Matt Porter8b657272006-10-26 17:12:59 +0200501static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
502 struct snd_ctl_elem_info *uinfo)
503{
504 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
505 struct sigmatel_spec *spec = codec->spec;
506 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
507}
508
509static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
510 struct snd_ctl_elem_value *ucontrol)
511{
512 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
513 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100514 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200515
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100516 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200517 return 0;
518}
519
520static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
521 struct snd_ctl_elem_value *ucontrol)
522{
523 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
524 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100525 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200526
527 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100528 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200529}
530
Matthew Ranostayd9737752008-09-07 12:03:41 +0200531static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
532 struct snd_ctl_elem_info *uinfo)
533{
534 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
535 struct sigmatel_spec *spec = codec->spec;
536 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
537}
538
539static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
540 struct snd_ctl_elem_value *ucontrol)
541{
542 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
543 struct sigmatel_spec *spec = codec->spec;
544 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
545
546 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
547 return 0;
548}
549
550static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
551 struct snd_ctl_elem_value *ucontrol)
552{
553 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
554 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400555 struct hda_input_mux *smux = &spec->private_smux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200556 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400557 int err, val;
558 hda_nid_t nid;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200559
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400560 err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200561 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400562 if (err < 0)
563 return err;
564
565 if (spec->spdif_mute) {
566 if (smux_idx == 0)
567 nid = spec->multiout.dig_out_nid;
568 else
569 nid = codec->slave_dig_outs[smux_idx - 1];
570 if (spec->cur_smux[smux_idx] == smux->num_items - 1)
571 val = AMP_OUT_MUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400572 else
Takashi Iwaic1e99bd2008-10-29 08:03:42 +0100573 val = AMP_OUT_UNMUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400574 /* un/mute SPDIF out */
575 snd_hda_codec_write_cache(codec, nid, 0,
576 AC_VERB_SET_AMP_GAIN_MUTE, val);
577 }
578 return 0;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200579}
580
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100581static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200582{
583 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
584 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200585 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200586}
587
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100588static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200589{
590 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
591 struct sigmatel_spec *spec = codec->spec;
592 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
593
594 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
595 return 0;
596}
597
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100598static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200599{
600 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
601 struct sigmatel_spec *spec = codec->spec;
602 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
603
Mattc7d4b2f2005-06-27 14:59:41 +0200604 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200605 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
606}
607
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100608static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
609 struct snd_ctl_elem_info *uinfo)
610{
611 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
612 struct sigmatel_spec *spec = codec->spec;
613 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
614}
615
616static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
617 struct snd_ctl_elem_value *ucontrol)
618{
619 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
620 struct sigmatel_spec *spec = codec->spec;
621
622 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
623 return 0;
624}
625
626static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
627 struct snd_ctl_elem_value *ucontrol)
628{
629 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
630 struct sigmatel_spec *spec = codec->spec;
631
632 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
633 spec->mono_nid, &spec->cur_mmux);
634}
635
Matthew Ranostay89385032008-09-11 09:49:39 -0400636static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
637 struct snd_ctl_elem_info *uinfo)
638{
639 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
640 struct sigmatel_spec *spec = codec->spec;
641 return snd_hda_input_mux_info(spec->amp_mux, uinfo);
642}
643
644static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
645 struct snd_ctl_elem_value *ucontrol)
646{
647 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
648 struct sigmatel_spec *spec = codec->spec;
649
650 ucontrol->value.enumerated.item[0] = spec->cur_amux;
651 return 0;
652}
653
654static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
655 struct snd_ctl_elem_value *ucontrol)
656{
657 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
658 struct sigmatel_spec *spec = codec->spec;
659 struct snd_kcontrol *ctl =
660 snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
661 if (!ctl)
662 return -EINVAL;
663
664 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
665 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
666
667 return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
668 0, &spec->cur_amux);
669}
670
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200671#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
672
673static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
674 struct snd_ctl_elem_value *ucontrol)
675{
676 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100677 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200678 struct sigmatel_spec *spec = codec->spec;
679
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100680 ucontrol->value.integer.value[0] = !!(spec->aloopback &
681 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200682 return 0;
683}
684
685static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
686 struct snd_ctl_elem_value *ucontrol)
687{
688 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
689 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100690 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200691 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200693
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100694 idx_val = spec->aloopback_mask << idx;
695 if (ucontrol->value.integer.value[0])
696 val = spec->aloopback | idx_val;
697 else
698 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100699 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200700 return 0;
701
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100702 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200703
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100704 /* Only return the bits defined by the shift value of the
705 * first two bytes of the mask
706 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200707 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100708 kcontrol->private_value & 0xFFFF, 0x0);
709 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200710
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100711 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200712 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100713 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200714 } else {
715 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100716 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200717 }
718
719 snd_hda_codec_write_cache(codec, codec->afg, 0,
720 kcontrol->private_value >> 16, dac_mode);
721
722 return 1;
723}
724
Mattc7d4b2f2005-06-27 14:59:41 +0200725static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200726 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200727 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200728 {}
729};
730
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200731static struct hda_verb stac9200_eapd_init[] = {
732 /* set dac0mux for dac converter */
733 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
734 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
735 {}
736};
737
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100738static struct hda_verb stac92hd73xx_6ch_core_init[] = {
739 /* set master volume and direct control */
740 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
741 /* setup audio connections */
742 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
743 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
744 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
745 /* setup adcs to point to mixer */
746 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
747 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100748 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
749 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
750 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
751 /* setup import muxs */
752 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
753 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
754 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
755 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
756 {}
757};
758
Matthew Ranostayd654a662008-03-14 08:46:51 +0100759static struct hda_verb dell_eq_core_init[] = {
760 /* set master volume to max value without distortion
761 * and direct control */
762 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
763 /* setup audio connections */
764 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
Matthew Ranostayf7cf0a72008-09-13 10:36:58 -0400765 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
766 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayd654a662008-03-14 08:46:51 +0100767 /* setup adcs to point to mixer */
768 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
769 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
770 /* setup import muxs */
771 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
772 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
773 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
774 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
775 {}
776};
777
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100778static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -0500779 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100780 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100781 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
782 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100783 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
784 /* setup adcs to point to mixer */
785 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
786 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
787 /* setup import muxs */
788 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
789 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
790 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
791 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
792 {}
793};
794
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100795static struct hda_verb stac92hd73xx_8ch_core_init[] = {
796 /* set master volume and direct control */
797 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
798 /* setup audio connections */
799 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
800 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
801 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
802 /* connect hp ports to dac3 */
803 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
804 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
805 /* setup adcs to point to mixer */
806 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
807 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100808 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
809 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
810 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
811 /* setup import muxs */
812 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
813 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
814 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
815 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
816 {}
817};
818
819static struct hda_verb stac92hd73xx_10ch_core_init[] = {
820 /* set master volume and direct control */
821 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
822 /* setup audio connections */
823 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
824 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
825 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
826 /* dac3 is connected to import3 mux */
827 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
828 /* connect hp ports to dac4 */
829 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
830 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
831 /* setup adcs to point to mixer */
832 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
833 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100834 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
835 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
836 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
837 /* setup import muxs */
838 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
839 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
840 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
841 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
842 {}
843};
844
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200845static struct hda_verb stac92hd83xxx_core_init[] = {
846 /* start of config #1 */
847 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
848
849 /* start of config #2 */
850 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
851 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
852 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
853
854 /* power state controls amps */
855 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
856};
857
Matthew Ranostaye035b842007-11-06 11:53:55 +0100858static struct hda_verb stac92hd71bxx_core_init[] = {
859 /* set master volume and direct control */
860 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
861 /* connect headphone jack to dac1 */
862 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100863 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
864 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
865 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
866 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100867};
868
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400869#define HD_DISABLE_PORTF 2
Matthew Ranostay541eee82007-12-14 12:08:04 +0100870static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200871 /* start of config #1 */
872
873 /* connect port 0f to audio mixer */
874 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200875 /* unmute right and left channels for node 0x0f */
876 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
877 /* start of config #2 */
878
Matthew Ranostay541eee82007-12-14 12:08:04 +0100879 /* set master volume and direct control */
880 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
881 /* connect headphone jack to dac1 */
882 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200883 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100884 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
885 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100886 {}
887};
888
Tobin Davis8e21c342007-01-08 11:04:17 +0100889static struct hda_verb stac925x_core_init[] = {
890 /* set dac0mux for dac converter */
891 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
892 {}
893};
894
Mattc7d4b2f2005-06-27 14:59:41 +0200895static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200896 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200897 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200898 {}
899};
900
Tobin Davis93ed1502006-09-01 21:03:12 +0200901static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200902 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200903 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200904 /* unmute node 0x1b */
905 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
906 /* select node 0x03 as DAC */
907 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
908 {}
909};
910
Matt Porter3cc08dc2006-01-23 15:27:49 +0100911static struct hda_verb stac927x_core_init[] = {
912 /* set master volume and direct control */
913 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200914 /* enable analog pc beep path */
915 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100916 {}
917};
918
Matt Porterf3302a52006-07-31 12:49:34 +0200919static struct hda_verb stac9205_core_init[] = {
920 /* set master volume and direct control */
921 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200922 /* enable analog pc beep path */
923 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200924 {}
925};
926
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100927#define STAC_MONO_MUX \
928 { \
929 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
930 .name = "Mono Mux", \
931 .count = 1, \
932 .info = stac92xx_mono_mux_enum_info, \
933 .get = stac92xx_mono_mux_enum_get, \
934 .put = stac92xx_mono_mux_enum_put, \
935 }
936
Matthew Ranostay89385032008-09-11 09:49:39 -0400937#define STAC_AMP_MUX \
938 { \
939 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
940 .name = "Amp Selector Capture Switch", \
941 .count = 1, \
942 .info = stac92xx_amp_mux_enum_info, \
943 .get = stac92xx_amp_mux_enum_get, \
944 .put = stac92xx_amp_mux_enum_put, \
945 }
946
947#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
948 { \
949 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
950 .name = xname, \
951 .index = 0, \
952 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
953 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
954 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
955 .info = stac92xx_amp_volume_info, \
956 .get = stac92xx_amp_volume_get, \
957 .put = stac92xx_amp_volume_put, \
958 .tlv = { .c = snd_hda_mixer_amp_tlv }, \
959 .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
960 }
961
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200962#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200963 { \
964 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
965 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200966 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200967 .info = stac92xx_mux_enum_info, \
968 .get = stac92xx_mux_enum_get, \
969 .put = stac92xx_mux_enum_put, \
970 }
971
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100972#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200973 { \
974 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
975 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100976 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200977 .info = stac92xx_aloopback_info, \
978 .get = stac92xx_aloopback_get, \
979 .put = stac92xx_aloopback_put, \
980 .private_value = verb_read | (verb_write << 16), \
981 }
982
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100983static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200984 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
985 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200986 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200987 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
988 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200989 { } /* end */
990};
991
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400992#define DELL_M6_MIXER 6
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100993static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400994 /* start of config #1 */
995 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
996 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
997
998 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
999 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1000
1001 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1002 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1003
1004 /* start of config #2 */
1005 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1006 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1007
1008 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1009 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1010
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001011 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
1012
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001013 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1014 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1015
1016 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1017 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1018
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001019 { } /* end */
1020};
1021
1022static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001023 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1024
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001025 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1026 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1027
1028 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1029 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1030
1031 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1032 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1033
1034 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1035 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1036
1037 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1038 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1039
1040 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1041 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1042
1043 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1044 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1045 { } /* end */
1046};
1047
1048static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001049 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1050
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001051 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1052 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1053
1054 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1055 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1056
1057 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1058 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1059
1060 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1061 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1062
1063 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1064 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1065
1066 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1067 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1068
1069 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1070 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1071 { } /* end */
1072};
1073
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001074
1075static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
1076 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
1077 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
1078
1079 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
1080 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
1081
1082 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
1083 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
1084
1085 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
1086 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
1087
1088 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
1089 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
1090
1091 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
1092 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
1093
1094 /*
1095 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
1096 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
1097 */
1098 { } /* end */
1099};
1100
Matthew Ranostay541eee82007-12-14 12:08:04 +01001101static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001102 STAC_INPUT_SOURCE(2),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001103 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001104
Matthew Ranostay9b359472007-11-07 13:03:12 +01001105 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1106 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +01001107
1108 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1109 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001110 /* analog pc-beep replaced with digital beep support */
1111 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001112 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
1113 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001114 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001115
Matthew Ranostay687cb98e2008-10-11 13:52:43 -04001116 HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
1117 HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001118
Matthew Ranostay687cb98e2008-10-11 13:52:43 -04001119 HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
1120 HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001121
1122 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
1123 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
1124
1125 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
1126 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001127 { } /* end */
1128};
1129
Matthew Ranostay541eee82007-12-14 12:08:04 +01001130static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +01001131 STAC_INPUT_SOURCE(2),
1132 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
1133
Matthew Ranostay541eee82007-12-14 12:08:04 +01001134 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1135 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001136
1137 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1138 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001139 { } /* end */
1140};
1141
Tobin Davis8e21c342007-01-08 11:04:17 +01001142static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001143 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001144 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001145 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001146 { } /* end */
1147};
1148
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001149static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001150 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001151 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001152
1153 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1154 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001155
1156 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1157 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001158 { } /* end */
1159};
1160
1161/* This needs to be generated dynamically based on sequence */
1162static struct snd_kcontrol_new stac922x_mixer[] = {
1163 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001164 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1165 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001166
1167 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1168 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001169 { } /* end */
1170};
1171
1172
1173static struct snd_kcontrol_new stac927x_mixer[] = {
1174 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001175 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001176
1177 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1178 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001179
1180 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1181 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001182
1183 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1184 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001185 { } /* end */
1186};
1187
Takashi Iwai16970552007-12-18 18:05:52 +01001188static struct snd_kcontrol_new stac_dmux_mixer = {
1189 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1190 .name = "Digital Input Source",
1191 /* count set later */
1192 .info = stac92xx_dmux_enum_info,
1193 .get = stac92xx_dmux_enum_get,
1194 .put = stac92xx_dmux_enum_put,
1195};
1196
Matthew Ranostayd9737752008-09-07 12:03:41 +02001197static struct snd_kcontrol_new stac_smux_mixer = {
1198 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001199 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001200 /* count set later */
1201 .info = stac92xx_smux_enum_info,
1202 .get = stac92xx_smux_enum_get,
1203 .put = stac92xx_smux_enum_put,
1204};
1205
Takashi Iwai2134ea42008-01-10 16:53:55 +01001206static const char *slave_vols[] = {
1207 "Front Playback Volume",
1208 "Surround Playback Volume",
1209 "Center Playback Volume",
1210 "LFE Playback Volume",
1211 "Side Playback Volume",
1212 "Headphone Playback Volume",
1213 "Headphone Playback Volume",
1214 "Speaker Playback Volume",
1215 "External Speaker Playback Volume",
1216 "Speaker2 Playback Volume",
1217 NULL
1218};
1219
1220static const char *slave_sws[] = {
1221 "Front Playback Switch",
1222 "Surround Playback Switch",
1223 "Center Playback Switch",
1224 "LFE Playback Switch",
1225 "Side Playback Switch",
1226 "Headphone Playback Switch",
1227 "Headphone Playback Switch",
1228 "Speaker Playback Switch",
1229 "External Speaker Playback Switch",
1230 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001231 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001232 NULL
1233};
1234
Matt2f2f4252005-04-13 14:45:30 +02001235static int stac92xx_build_controls(struct hda_codec *codec)
1236{
1237 struct sigmatel_spec *spec = codec->spec;
1238 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001239 int i;
Matt2f2f4252005-04-13 14:45:30 +02001240
1241 err = snd_hda_add_new_ctls(codec, spec->mixer);
1242 if (err < 0)
1243 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001244
1245 for (i = 0; i < spec->num_mixers; i++) {
1246 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1247 if (err < 0)
1248 return err;
1249 }
Takashi Iwai16970552007-12-18 18:05:52 +01001250 if (spec->num_dmuxes > 0) {
1251 stac_dmux_mixer.count = spec->num_dmuxes;
1252 err = snd_ctl_add(codec->bus->card,
1253 snd_ctl_new1(&stac_dmux_mixer, codec));
1254 if (err < 0)
1255 return err;
1256 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001257 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001258 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1259 struct hda_input_mux *smux = &spec->private_smux;
1260 /* check for mute support on SPDIF out */
1261 if (wcaps & AC_WCAP_OUT_AMP) {
1262 smux->items[smux->num_items].label = "Off";
1263 smux->items[smux->num_items].index = 0;
1264 smux->num_items++;
1265 spec->spdif_mute = 1;
1266 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001267 stac_smux_mixer.count = spec->num_smuxes;
1268 err = snd_ctl_add(codec->bus->card,
1269 snd_ctl_new1(&stac_smux_mixer, codec));
1270 if (err < 0)
1271 return err;
1272 }
Mattc7d4b2f2005-06-27 14:59:41 +02001273
Mattdabbed62005-06-14 10:19:34 +02001274 if (spec->multiout.dig_out_nid) {
1275 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1276 if (err < 0)
1277 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001278 err = snd_hda_create_spdif_share_sw(codec,
1279 &spec->multiout);
1280 if (err < 0)
1281 return err;
1282 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001283 }
Harvey Harrisonda74ae32008-10-21 20:28:04 -07001284 if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001285 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1286 if (err < 0)
1287 return err;
1288 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001289
1290 /* if we have no master control, let's create it */
1291 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001292 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001293 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001294 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001295 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001296 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001297 if (err < 0)
1298 return err;
1299 }
1300 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1301 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1302 NULL, slave_sws);
1303 if (err < 0)
1304 return err;
1305 }
1306
Mattdabbed62005-06-14 10:19:34 +02001307 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001308}
1309
Matt Porter403d1942005-11-29 15:00:51 +01001310static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001311 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001312 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1313};
1314
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001315/*
1316 STAC 9200 pin configs for
1317 102801A8
1318 102801DE
1319 102801E8
1320*/
1321static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001322 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1323 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001324};
1325
1326/*
1327 STAC 9200 pin configs for
1328 102801C0
1329 102801C1
1330*/
1331static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001332 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1333 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001334};
1335
1336/*
1337 STAC 9200 pin configs for
1338 102801C4 (Dell Dimension E310)
1339 102801C5
1340 102801C7
1341 102801D9
1342 102801DA
1343 102801E3
1344*/
1345static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001346 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1347 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001348};
1349
1350
1351/*
1352 STAC 9200-32 pin configs for
1353 102801B5 (Dell Inspiron 630m)
1354 102801D8 (Dell Inspiron 640m)
1355*/
1356static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001357 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1358 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001359};
1360
1361/*
1362 STAC 9200-32 pin configs for
1363 102801C2 (Dell Latitude D620)
1364 102801C8
1365 102801CC (Dell Latitude D820)
1366 102801D4
1367 102801D6
1368*/
1369static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001370 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1371 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001372};
1373
1374/*
1375 STAC 9200-32 pin configs for
1376 102801CE (Dell XPS M1710)
1377 102801CF (Dell Precision M90)
1378*/
1379static unsigned int dell9200_m23_pin_configs[8] = {
1380 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1381 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1382};
1383
1384/*
1385 STAC 9200-32 pin configs for
1386 102801C9
1387 102801CA
1388 102801CB (Dell Latitude 120L)
1389 102801D3
1390*/
1391static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001392 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1393 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001394};
1395
1396/*
1397 STAC 9200-32 pin configs for
1398 102801BD (Dell Inspiron E1505n)
1399 102801EE
1400 102801EF
1401*/
1402static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001403 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1404 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001405};
1406
1407/*
1408 STAC 9200-32 pin configs for
1409 102801F5 (Dell Inspiron 1501)
1410 102801F6
1411*/
1412static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001413 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1414 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001415};
1416
1417/*
1418 STAC 9200-32
1419 102801CD (Dell Inspiron E1705/9400)
1420*/
1421static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001422 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1423 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001424};
1425
Tobin Davisbf277782008-02-03 20:31:47 +01001426static unsigned int oqo9200_pin_configs[8] = {
1427 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1428 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1429};
1430
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001431
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001432static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1433 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001434 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001435 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1436 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1437 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1438 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1439 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1440 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1441 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1442 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1443 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1444 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001445 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001446};
1447
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001448static const char *stac9200_models[STAC_9200_MODELS] = {
1449 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001450 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001451 [STAC_9200_DELL_D21] = "dell-d21",
1452 [STAC_9200_DELL_D22] = "dell-d22",
1453 [STAC_9200_DELL_D23] = "dell-d23",
1454 [STAC_9200_DELL_M21] = "dell-m21",
1455 [STAC_9200_DELL_M22] = "dell-m22",
1456 [STAC_9200_DELL_M23] = "dell-m23",
1457 [STAC_9200_DELL_M24] = "dell-m24",
1458 [STAC_9200_DELL_M25] = "dell-m25",
1459 [STAC_9200_DELL_M26] = "dell-m26",
1460 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001461 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001462 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001463};
1464
1465static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1466 /* SigmaTel reference board */
1467 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1468 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001469 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001470 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1471 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001472 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001473 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1474 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1475 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1476 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1477 "unknown Dell", STAC_9200_DELL_D22),
1478 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1479 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001480 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001481 "Dell Latitude D620", STAC_9200_DELL_M22),
1482 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1483 "unknown Dell", STAC_9200_DELL_D23),
1484 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1485 "unknown Dell", STAC_9200_DELL_D23),
1486 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1487 "unknown Dell", STAC_9200_DELL_M22),
1488 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1489 "unknown Dell", STAC_9200_DELL_M24),
1490 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1491 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001492 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001493 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001494 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001495 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001496 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001497 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001498 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001499 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001500 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001501 "Dell Precision M90", STAC_9200_DELL_M23),
1502 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1503 "unknown Dell", STAC_9200_DELL_M22),
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1505 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001506 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001507 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001508 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001509 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1510 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1511 "unknown Dell", STAC_9200_DELL_D23),
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1513 "unknown Dell", STAC_9200_DELL_D23),
1514 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1515 "unknown Dell", STAC_9200_DELL_D21),
1516 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1517 "unknown Dell", STAC_9200_DELL_D23),
1518 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1519 "unknown Dell", STAC_9200_DELL_D21),
1520 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1521 "unknown Dell", STAC_9200_DELL_M25),
1522 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1523 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001524 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001525 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1527 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001528 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001529 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001530 /* Gateway machines needs EAPD to be set on resume */
1531 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1532 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1533 STAC_9200_GATEWAY),
1534 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1535 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001536 /* OQO Mobile */
1537 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001538 {} /* terminator */
1539};
1540
Tobin Davis8e21c342007-01-08 11:04:17 +01001541static unsigned int ref925x_pin_configs[8] = {
1542 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001543 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001544};
1545
1546static unsigned int stac925x_MA6_pin_configs[8] = {
1547 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1548 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1549};
1550
Tobin Davis2c11f952007-05-17 09:36:34 +02001551static unsigned int stac925x_PA6_pin_configs[8] = {
1552 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1553 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1554};
1555
Tobin Davis8e21c342007-01-08 11:04:17 +01001556static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001557 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1558 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001559};
1560
1561static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1562 [STAC_REF] = ref925x_pin_configs,
1563 [STAC_M2_2] = stac925xM2_2_pin_configs,
1564 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001565 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001566};
1567
1568static const char *stac925x_models[STAC_925x_MODELS] = {
1569 [STAC_REF] = "ref",
1570 [STAC_M2_2] = "m2-2",
1571 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001572 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001573};
1574
1575static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1576 /* SigmaTel reference board */
1577 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001578 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001579 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1580 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1581 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001582 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001583 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1584 {} /* terminator */
1585};
1586
Matthew Ranostaya7662642008-02-21 07:51:14 +01001587static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001588 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1589 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1590 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001591 0x01452050,
1592};
1593
1594static unsigned int dell_m6_pin_configs[13] = {
1595 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001596 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001597 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1598 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001599};
1600
1601static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001602 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1603 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001604 [STAC_DELL_EQ] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001605};
1606
1607static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1608 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001609 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001610 [STAC_DELL_EQ] = "dell-eq",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001611};
1612
1613static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1614 /* SigmaTel reference board */
1615 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001616 "DFI LanParty", STAC_92HD73XX_REF),
1617 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1618 "unknown Dell", STAC_DELL_M6),
1619 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1620 "unknown Dell", STAC_DELL_M6),
1621 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1622 "unknown Dell", STAC_DELL_M6),
1623 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1624 "unknown Dell", STAC_DELL_M6),
1625 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1626 "unknown Dell", STAC_DELL_M6),
1627 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1628 "unknown Dell", STAC_DELL_M6),
1629 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1630 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001631 {} /* terminator */
1632};
1633
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001634static unsigned int ref92hd83xxx_pin_configs[14] = {
1635 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1636 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1637 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1638 0x01451160, 0x98560170,
1639};
1640
1641static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1642 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1643};
1644
1645static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1646 [STAC_92HD83XXX_REF] = "ref",
1647};
1648
1649static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1650 /* SigmaTel reference board */
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1652 "DFI LanParty", STAC_92HD71BXX_REF),
1653};
1654
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001655static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001656 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001657 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001658 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001659};
1660
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001661static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001662 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001663 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001664 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001665};
1666
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001667static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001668 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1669 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001670 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001671};
1672
Matthew Ranostaye035b842007-11-06 11:53:55 +01001673static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1674 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001675 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1676 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001677 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001678};
1679
1680static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1681 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001682 [STAC_DELL_M4_1] = "dell-m4-1",
1683 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001684 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001685};
1686
1687static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1688 /* SigmaTel reference board */
1689 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1690 "DFI LanParty", STAC_92HD71BXX_REF),
Takashi Iwai80bf2722008-11-18 10:48:41 +01001691 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
1692 "HP dv5", STAC_HP_M4),
1693 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
1694 "HP dv7", STAC_HP_M4),
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04001695 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
1696 "unknown HP", STAC_HP_M4),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001697 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1698 "unknown Dell", STAC_DELL_M4_1),
1699 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1700 "unknown Dell", STAC_DELL_M4_1),
1701 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1702 "unknown Dell", STAC_DELL_M4_1),
1703 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1704 "unknown Dell", STAC_DELL_M4_1),
1705 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1706 "unknown Dell", STAC_DELL_M4_1),
1707 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1708 "unknown Dell", STAC_DELL_M4_1),
1709 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1710 "unknown Dell", STAC_DELL_M4_1),
1711 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1712 "unknown Dell", STAC_DELL_M4_2),
1713 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1714 "unknown Dell", STAC_DELL_M4_2),
1715 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1716 "unknown Dell", STAC_DELL_M4_2),
1717 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1718 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001719 {} /* terminator */
1720};
1721
Matt Porter403d1942005-11-29 15:00:51 +01001722static unsigned int ref922x_pin_configs[10] = {
1723 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1724 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001725 0x40000100, 0x40000100,
1726};
1727
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001728/*
1729 STAC 922X pin configs for
1730 102801A7
1731 102801AB
1732 102801A9
1733 102801D1
1734 102801D2
1735*/
1736static unsigned int dell_922x_d81_pin_configs[10] = {
1737 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1738 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1739 0x01813122, 0x400001f2,
1740};
1741
1742/*
1743 STAC 922X pin configs for
1744 102801AC
1745 102801D0
1746*/
1747static unsigned int dell_922x_d82_pin_configs[10] = {
1748 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1749 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1750 0x01813122, 0x400001f1,
1751};
1752
1753/*
1754 STAC 922X pin configs for
1755 102801BF
1756*/
1757static unsigned int dell_922x_m81_pin_configs[10] = {
1758 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1759 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1760 0x40C003f1, 0x405003f0,
1761};
1762
1763/*
1764 STAC 9221 A1 pin configs for
1765 102801D7 (Dell XPS M1210)
1766*/
1767static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001768 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1769 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001770 0x508003f3, 0x405003f4,
1771};
1772
Matt Porter403d1942005-11-29 15:00:51 +01001773static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001774 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001775 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1776 0x02a19120, 0x40000100,
1777};
1778
1779static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001780 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1781 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001782 0x02a19320, 0x40000100,
1783};
1784
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001785static unsigned int intel_mac_v1_pin_configs[10] = {
1786 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1787 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001788 0x400000fc, 0x400000fb,
1789};
1790
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001791static unsigned int intel_mac_v2_pin_configs[10] = {
1792 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1793 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001794 0x400000fc, 0x400000fb,
1795};
1796
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001797static unsigned int intel_mac_v3_pin_configs[10] = {
1798 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1799 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1800 0x400000fc, 0x400000fb,
1801};
1802
1803static unsigned int intel_mac_v4_pin_configs[10] = {
1804 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1805 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1806 0x400000fc, 0x400000fb,
1807};
1808
1809static unsigned int intel_mac_v5_pin_configs[10] = {
1810 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1811 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1812 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001813};
1814
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001815static unsigned int ecs202_pin_configs[10] = {
1816 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1817 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1818 0x9037012e, 0x40e000f2,
1819};
Takashi Iwai76c08822007-06-19 12:17:42 +02001820
Takashi Iwai19039bd2006-06-28 15:52:16 +02001821static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001822 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001823 [STAC_D945GTP3] = d945gtp3_pin_configs,
1824 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001825 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1826 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1827 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1828 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1829 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001830 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001831 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001832 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1833 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1834 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1835 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1836 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1837 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001838 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001839 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1840 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1841 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1842 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001843};
1844
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001845static const char *stac922x_models[STAC_922X_MODELS] = {
1846 [STAC_D945_REF] = "ref",
1847 [STAC_D945GTP5] = "5stack",
1848 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001849 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1850 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1851 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1852 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1853 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001854 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001855 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001856 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001857 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001858 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1859 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001860 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001861 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001862 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001863 [STAC_922X_DELL_D81] = "dell-d81",
1864 [STAC_922X_DELL_D82] = "dell-d82",
1865 [STAC_922X_DELL_M81] = "dell-m81",
1866 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001867};
1868
1869static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1870 /* SigmaTel reference board */
1871 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1872 "DFI LanParty", STAC_D945_REF),
1873 /* Intel 945G based systems */
1874 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1875 "Intel D945G", STAC_D945GTP3),
1876 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1877 "Intel D945G", STAC_D945GTP3),
1878 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1879 "Intel D945G", STAC_D945GTP3),
1880 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1881 "Intel D945G", STAC_D945GTP3),
1882 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1883 "Intel D945G", STAC_D945GTP3),
1884 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1885 "Intel D945G", STAC_D945GTP3),
1886 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1887 "Intel D945G", STAC_D945GTP3),
1888 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1889 "Intel D945G", STAC_D945GTP3),
1890 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1891 "Intel D945G", STAC_D945GTP3),
1892 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1893 "Intel D945G", STAC_D945GTP3),
1894 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1895 "Intel D945G", STAC_D945GTP3),
1896 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1897 "Intel D945G", STAC_D945GTP3),
1898 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1899 "Intel D945G", STAC_D945GTP3),
1900 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1901 "Intel D945G", STAC_D945GTP3),
1902 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1903 "Intel D945G", STAC_D945GTP3),
1904 /* Intel D945G 5-stack systems */
1905 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1906 "Intel D945G", STAC_D945GTP5),
1907 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1908 "Intel D945G", STAC_D945GTP5),
1909 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1910 "Intel D945G", STAC_D945GTP5),
1911 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1912 "Intel D945G", STAC_D945GTP5),
1913 /* Intel 945P based systems */
1914 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1915 "Intel D945P", STAC_D945GTP3),
1916 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1917 "Intel D945P", STAC_D945GTP3),
1918 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1919 "Intel D945P", STAC_D945GTP3),
1920 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1921 "Intel D945P", STAC_D945GTP3),
1922 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1923 "Intel D945P", STAC_D945GTP3),
1924 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1925 "Intel D945P", STAC_D945GTP5),
1926 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001927 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001928 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001929 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001930 /* Dell systems */
1931 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1932 "unknown Dell", STAC_922X_DELL_D81),
1933 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1934 "unknown Dell", STAC_922X_DELL_D81),
1935 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1936 "unknown Dell", STAC_922X_DELL_D81),
1937 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1938 "unknown Dell", STAC_922X_DELL_D82),
1939 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1940 "unknown Dell", STAC_922X_DELL_M81),
1941 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1942 "unknown Dell", STAC_922X_DELL_D82),
1943 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1944 "unknown Dell", STAC_922X_DELL_D81),
1945 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1946 "unknown Dell", STAC_922X_DELL_D81),
1947 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1948 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001949 /* ECS/PC Chips boards */
1950 SND_PCI_QUIRK(0x1019, 0x2144,
1951 "ECS/PC chips", STAC_ECS_202),
1952 SND_PCI_QUIRK(0x1019, 0x2608,
1953 "ECS/PC chips", STAC_ECS_202),
1954 SND_PCI_QUIRK(0x1019, 0x2633,
1955 "ECS/PC chips P17G/1333", STAC_ECS_202),
1956 SND_PCI_QUIRK(0x1019, 0x2811,
1957 "ECS/PC chips", STAC_ECS_202),
1958 SND_PCI_QUIRK(0x1019, 0x2812,
1959 "ECS/PC chips", STAC_ECS_202),
1960 SND_PCI_QUIRK(0x1019, 0x2813,
1961 "ECS/PC chips", STAC_ECS_202),
1962 SND_PCI_QUIRK(0x1019, 0x2814,
1963 "ECS/PC chips", STAC_ECS_202),
1964 SND_PCI_QUIRK(0x1019, 0x2815,
1965 "ECS/PC chips", STAC_ECS_202),
1966 SND_PCI_QUIRK(0x1019, 0x2816,
1967 "ECS/PC chips", STAC_ECS_202),
1968 SND_PCI_QUIRK(0x1019, 0x2817,
1969 "ECS/PC chips", STAC_ECS_202),
1970 SND_PCI_QUIRK(0x1019, 0x2818,
1971 "ECS/PC chips", STAC_ECS_202),
1972 SND_PCI_QUIRK(0x1019, 0x2819,
1973 "ECS/PC chips", STAC_ECS_202),
1974 SND_PCI_QUIRK(0x1019, 0x2820,
1975 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001976 {} /* terminator */
1977};
1978
Matt Porter3cc08dc2006-01-23 15:27:49 +01001979static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001980 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1981 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1982 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1983 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001984};
1985
Tobin Davis93ed1502006-09-01 21:03:12 +02001986static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001987 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1988 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1989 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1990 0x40000100, 0x40000100
1991};
1992
Tobin Davis93ed1502006-09-01 21:03:12 +02001993static unsigned int d965_5st_pin_configs[14] = {
1994 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1995 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1996 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1997 0x40000100, 0x40000100
1998};
1999
Tobin Davis4ff076e2007-08-07 11:48:12 +02002000static unsigned int dell_3st_pin_configs[14] = {
2001 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
2002 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002003 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02002004 0x40c003fc, 0x40000100
2005};
2006
Tobin Davis93ed1502006-09-01 21:03:12 +02002007static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002008 [STAC_D965_REF] = ref927x_pin_configs,
2009 [STAC_D965_3ST] = d965_3st_pin_configs,
2010 [STAC_D965_5ST] = d965_5st_pin_configs,
2011 [STAC_DELL_3ST] = dell_3st_pin_configs,
2012 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002013};
2014
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002015static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002016 [STAC_D965_REF] = "ref",
2017 [STAC_D965_3ST] = "3stack",
2018 [STAC_D965_5ST] = "5stack",
2019 [STAC_DELL_3ST] = "dell-3stack",
2020 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002021};
2022
2023static struct snd_pci_quirk stac927x_cfg_tbl[] = {
2024 /* SigmaTel reference board */
2025 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2026 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002027 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002028 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2029 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002030 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002031 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
2032 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
2033 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
2034 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
2035 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
2036 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
2037 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
2038 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
2039 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
2040 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
2041 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
2042 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
2043 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
2044 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
2045 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
2046 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002047 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002048 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002049 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002050 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2051 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002052 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002053 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
2054 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002055 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02002056 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002057 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2058 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2059 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2060 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002061 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002062 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
2063 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
2064 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
2065 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
2066 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
2067 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
2068 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
2069 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
2070 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002071 {} /* terminator */
2072};
2073
Matt Porterf3302a52006-07-31 12:49:34 +02002074static unsigned int ref9205_pin_configs[12] = {
2075 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002076 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02002077 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02002078};
2079
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002080/*
2081 STAC 9205 pin configs for
2082 102801F1
2083 102801F2
2084 102801FC
2085 102801FD
2086 10280204
2087 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002088 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002089*/
2090static unsigned int dell_9205_m42_pin_configs[12] = {
2091 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
2092 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
2093 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
2094};
2095
2096/*
2097 STAC 9205 pin configs for
2098 102801F9
2099 102801FA
2100 102801FE
2101 102801FF (Dell Precision M4300)
2102 10280206
2103 10280200
2104 10280201
2105*/
2106static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002107 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
2108 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
2109 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
2110};
2111
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002112static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002113 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
2114 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
2115 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
2116};
2117
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002118static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002119 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002120 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
2121 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
2122 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02002123};
2124
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002125static const char *stac9205_models[STAC_9205_MODELS] = {
2126 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002127 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002128 [STAC_9205_DELL_M43] = "dell-m43",
2129 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002130};
2131
2132static struct snd_pci_quirk stac9205_cfg_tbl[] = {
2133 /* SigmaTel reference board */
2134 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2135 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2137 "unknown Dell", STAC_9205_DELL_M42),
2138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2139 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002141 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002142 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2143 "Dell Precision", STAC_9205_DELL_M43),
2144 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2145 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002146 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2147 "unknown Dell", STAC_9205_DELL_M42),
2148 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2149 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002150 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2151 "Dell Precision", STAC_9205_DELL_M43),
2152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002153 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002154 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2155 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002156 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2157 "Dell Precision", STAC_9205_DELL_M43),
2158 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2159 "Dell Precision", STAC_9205_DELL_M43),
2160 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2161 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002162 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2163 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002164 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2165 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002166 {} /* terminator */
2167};
2168
Richard Fish11b44bb2006-08-23 18:31:34 +02002169static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2170{
2171 int i;
2172 struct sigmatel_spec *spec = codec->spec;
2173
2174 if (! spec->bios_pin_configs) {
2175 spec->bios_pin_configs = kcalloc(spec->num_pins,
2176 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2177 if (! spec->bios_pin_configs)
2178 return -ENOMEM;
2179 }
2180
2181 for (i = 0; i < spec->num_pins; i++) {
2182 hda_nid_t nid = spec->pin_nids[i];
2183 unsigned int pin_cfg;
2184
2185 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2186 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2187 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2188 nid, pin_cfg);
2189 spec->bios_pin_configs[i] = pin_cfg;
2190 }
2191
2192 return 0;
2193}
2194
Matthew Ranostay87d48362007-07-17 11:52:24 +02002195static void stac92xx_set_config_reg(struct hda_codec *codec,
2196 hda_nid_t pin_nid, unsigned int pin_config)
2197{
2198 int i;
2199 snd_hda_codec_write(codec, pin_nid, 0,
2200 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2201 pin_config & 0x000000ff);
2202 snd_hda_codec_write(codec, pin_nid, 0,
2203 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2204 (pin_config & 0x0000ff00) >> 8);
2205 snd_hda_codec_write(codec, pin_nid, 0,
2206 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2207 (pin_config & 0x00ff0000) >> 16);
2208 snd_hda_codec_write(codec, pin_nid, 0,
2209 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2210 pin_config >> 24);
2211 i = snd_hda_codec_read(codec, pin_nid, 0,
2212 AC_VERB_GET_CONFIG_DEFAULT,
2213 0x00);
2214 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2215 pin_nid, i);
2216}
2217
Matt2f2f4252005-04-13 14:45:30 +02002218static void stac92xx_set_config_regs(struct hda_codec *codec)
2219{
2220 int i;
2221 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002222
Matthew Ranostay87d48362007-07-17 11:52:24 +02002223 if (!spec->pin_configs)
2224 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002225
Matthew Ranostay87d48362007-07-17 11:52:24 +02002226 for (i = 0; i < spec->num_pins; i++)
2227 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2228 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002229}
Matt2f2f4252005-04-13 14:45:30 +02002230
Matt2f2f4252005-04-13 14:45:30 +02002231/*
2232 * Analog playback callbacks
2233 */
2234static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2235 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002236 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002237{
2238 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002239 if (spec->stream_delay)
2240 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002241 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2242 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002243}
2244
2245static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2246 struct hda_codec *codec,
2247 unsigned int stream_tag,
2248 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002249 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002250{
2251 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002252 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002253}
2254
2255static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2256 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002257 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002258{
2259 struct sigmatel_spec *spec = codec->spec;
2260 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2261}
2262
2263/*
Mattdabbed62005-06-14 10:19:34 +02002264 * Digital playback callbacks
2265 */
2266static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2267 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002268 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002269{
2270 struct sigmatel_spec *spec = codec->spec;
2271 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2272}
2273
2274static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2275 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002276 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002277{
2278 struct sigmatel_spec *spec = codec->spec;
2279 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2280}
2281
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002282static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2283 struct hda_codec *codec,
2284 unsigned int stream_tag,
2285 unsigned int format,
2286 struct snd_pcm_substream *substream)
2287{
2288 struct sigmatel_spec *spec = codec->spec;
2289 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2290 stream_tag, format, substream);
2291}
2292
Mattdabbed62005-06-14 10:19:34 +02002293
2294/*
Matt2f2f4252005-04-13 14:45:30 +02002295 * Analog capture callbacks
2296 */
2297static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2298 struct hda_codec *codec,
2299 unsigned int stream_tag,
2300 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002301 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002302{
2303 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002304 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002305
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002306 if (spec->powerdown_adcs) {
2307 msleep(40);
2308 snd_hda_codec_write_cache(codec, nid, 0,
2309 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2310 }
2311 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002312 return 0;
2313}
2314
2315static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2316 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002317 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002318{
2319 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002320 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002321
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002322 snd_hda_codec_cleanup_stream(codec, nid);
2323 if (spec->powerdown_adcs)
2324 snd_hda_codec_write_cache(codec, nid, 0,
2325 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002326 return 0;
2327}
2328
Mattdabbed62005-06-14 10:19:34 +02002329static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2330 .substreams = 1,
2331 .channels_min = 2,
2332 .channels_max = 2,
2333 /* NID is set in stac92xx_build_pcms */
2334 .ops = {
2335 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002336 .close = stac92xx_dig_playback_pcm_close,
2337 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002338 },
2339};
2340
2341static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2342 .substreams = 1,
2343 .channels_min = 2,
2344 .channels_max = 2,
2345 /* NID is set in stac92xx_build_pcms */
2346};
2347
Matt2f2f4252005-04-13 14:45:30 +02002348static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2349 .substreams = 1,
2350 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002351 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002352 .nid = 0x02, /* NID to query formats and rates */
2353 .ops = {
2354 .open = stac92xx_playback_pcm_open,
2355 .prepare = stac92xx_playback_pcm_prepare,
2356 .cleanup = stac92xx_playback_pcm_cleanup
2357 },
2358};
2359
Matt Porter3cc08dc2006-01-23 15:27:49 +01002360static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2361 .substreams = 1,
2362 .channels_min = 2,
2363 .channels_max = 2,
2364 .nid = 0x06, /* NID to query formats and rates */
2365 .ops = {
2366 .open = stac92xx_playback_pcm_open,
2367 .prepare = stac92xx_playback_pcm_prepare,
2368 .cleanup = stac92xx_playback_pcm_cleanup
2369 },
2370};
2371
Matt2f2f4252005-04-13 14:45:30 +02002372static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002373 .channels_min = 2,
2374 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002375 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002376 .ops = {
2377 .prepare = stac92xx_capture_pcm_prepare,
2378 .cleanup = stac92xx_capture_pcm_cleanup
2379 },
2380};
2381
2382static int stac92xx_build_pcms(struct hda_codec *codec)
2383{
2384 struct sigmatel_spec *spec = codec->spec;
2385 struct hda_pcm *info = spec->pcm_rec;
2386
2387 codec->num_pcms = 1;
2388 codec->pcm_info = info;
2389
Mattc7d4b2f2005-06-27 14:59:41 +02002390 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002391 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002392 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002393 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002394 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002395
2396 if (spec->alt_switch) {
2397 codec->num_pcms++;
2398 info++;
2399 info->name = "STAC92xx Analog Alt";
2400 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2401 }
Matt2f2f4252005-04-13 14:45:30 +02002402
Mattdabbed62005-06-14 10:19:34 +02002403 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2404 codec->num_pcms++;
2405 info++;
2406 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002407 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002408 if (spec->multiout.dig_out_nid) {
2409 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2410 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2411 }
2412 if (spec->dig_in_nid) {
2413 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2414 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2415 }
2416 }
2417
Matt2f2f4252005-04-13 14:45:30 +02002418 return 0;
2419}
2420
Takashi Iwaic960a032006-03-23 17:06:28 +01002421static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2422{
2423 unsigned int pincap = snd_hda_param_read(codec, nid,
2424 AC_PAR_PIN_CAP);
2425 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2426 if (pincap & AC_PINCAP_VREF_100)
2427 return AC_PINCTL_VREF_100;
2428 if (pincap & AC_PINCAP_VREF_80)
2429 return AC_PINCTL_VREF_80;
2430 if (pincap & AC_PINCAP_VREF_50)
2431 return AC_PINCTL_VREF_50;
2432 if (pincap & AC_PINCAP_VREF_GRD)
2433 return AC_PINCTL_VREF_GRD;
2434 return 0;
2435}
2436
Matt Porter403d1942005-11-29 15:00:51 +01002437static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2438
2439{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002440 snd_hda_codec_write_cache(codec, nid, 0,
2441 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002442}
2443
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002444#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2445
2446static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2447 struct snd_ctl_elem_value *ucontrol)
2448{
2449 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2450 struct sigmatel_spec *spec = codec->spec;
2451
Takashi Iwaid7a89432008-11-12 09:48:04 +01002452 ucontrol->value.integer.value[0] = !!spec->hp_switch;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002453 return 0;
2454}
2455
2456static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2457 struct snd_ctl_elem_value *ucontrol)
2458{
2459 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2460 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaid7a89432008-11-12 09:48:04 +01002461 int nid = kcontrol->private_value;
2462
2463 spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002464
2465 /* check to be sure that the ports are upto date with
2466 * switch changes
2467 */
2468 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2469
2470 return 1;
2471}
2472
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002473#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002474
2475static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2476{
2477 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2478 struct sigmatel_spec *spec = codec->spec;
2479 int io_idx = kcontrol-> private_value & 0xff;
2480
2481 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2482 return 0;
2483}
2484
2485static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2486{
2487 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2488 struct sigmatel_spec *spec = codec->spec;
2489 hda_nid_t nid = kcontrol->private_value >> 8;
2490 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002491 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002492
2493 spec->io_switch[io_idx] = val;
2494
2495 if (val)
2496 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002497 else {
2498 unsigned int pinctl = AC_PINCTL_IN_EN;
2499 if (io_idx) /* set VREF for mic */
2500 pinctl |= stac92xx_get_vref(codec, nid);
2501 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2502 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002503
2504 /* check the auto-mute again: we need to mute/unmute the speaker
2505 * appropriately according to the pin direction
2506 */
2507 if (spec->hp_detect)
2508 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2509
Matt Porter403d1942005-11-29 15:00:51 +01002510 return 1;
2511}
2512
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002513#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2514
2515static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2516 struct snd_ctl_elem_value *ucontrol)
2517{
2518 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2519 struct sigmatel_spec *spec = codec->spec;
2520
2521 ucontrol->value.integer.value[0] = spec->clfe_swap;
2522 return 0;
2523}
2524
2525static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2526 struct snd_ctl_elem_value *ucontrol)
2527{
2528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2529 struct sigmatel_spec *spec = codec->spec;
2530 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002531 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002532
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002533 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002534 return 0;
2535
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002536 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002537
2538 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2539 spec->clfe_swap ? 0x4 : 0x0);
2540
2541 return 1;
2542}
2543
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002544#define STAC_CODEC_HP_SWITCH(xname) \
2545 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2546 .name = xname, \
2547 .index = 0, \
2548 .info = stac92xx_hp_switch_info, \
2549 .get = stac92xx_hp_switch_get, \
2550 .put = stac92xx_hp_switch_put, \
2551 }
2552
Matt Porter403d1942005-11-29 15:00:51 +01002553#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2554 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2555 .name = xname, \
2556 .index = 0, \
2557 .info = stac92xx_io_switch_info, \
2558 .get = stac92xx_io_switch_get, \
2559 .put = stac92xx_io_switch_put, \
2560 .private_value = xpval, \
2561 }
2562
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002563#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2564 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2565 .name = xname, \
2566 .index = 0, \
2567 .info = stac92xx_clfe_switch_info, \
2568 .get = stac92xx_clfe_switch_get, \
2569 .put = stac92xx_clfe_switch_put, \
2570 .private_value = xpval, \
2571 }
Matt Porter403d1942005-11-29 15:00:51 +01002572
Mattc7d4b2f2005-06-27 14:59:41 +02002573enum {
2574 STAC_CTL_WIDGET_VOL,
2575 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002576 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002577 STAC_CTL_WIDGET_AMP_MUX,
2578 STAC_CTL_WIDGET_AMP_VOL,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002579 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002580 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002581 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002582};
2583
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002584static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002585 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2586 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002587 STAC_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002588 STAC_AMP_MUX,
2589 STAC_AMP_VOL(NULL, 0, 0, 0, 0),
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002590 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002591 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002592 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002593};
2594
2595/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002596static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
2597 struct snd_kcontrol_new *ktemp,
2598 int idx, const char *name,
2599 unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002600{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002601 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002602
2603 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2604 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2605
2606 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2607 if (! knew)
2608 return -ENOMEM;
2609 if (spec->kctl_alloc) {
2610 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2611 kfree(spec->kctl_alloc);
2612 }
2613 spec->kctl_alloc = knew;
2614 spec->num_kctl_alloc = num;
2615 }
2616
2617 knew = &spec->kctl_alloc[spec->num_kctl_used];
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002618 *knew = *ktemp;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002619 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002620 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002621 if (!knew->name)
Mattc7d4b2f2005-06-27 14:59:41 +02002622 return -ENOMEM;
2623 knew->private_value = val;
2624 spec->num_kctl_used++;
2625 return 0;
2626}
2627
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002628static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
2629 int type, int idx, const char *name,
2630 unsigned long val)
2631{
2632 return stac92xx_add_control_temp(spec,
2633 &stac92xx_control_templates[type],
2634 idx, name, val);
2635}
2636
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002637
2638/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002639static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2640 const char *name, unsigned long val)
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002641{
2642 return stac92xx_add_control_idx(spec, type, 0, name, val);
2643}
2644
Matt Porter403d1942005-11-29 15:00:51 +01002645/* flag inputs as additional dynamic lineouts */
2646static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2647{
2648 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002649 unsigned int wcaps, wtype;
2650 int i, num_dacs = 0;
2651
2652 /* use the wcaps cache to count all DACs available for line-outs */
2653 for (i = 0; i < codec->num_nodes; i++) {
2654 wcaps = codec->wcaps[i];
2655 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002656
Steve Longerbeam7b043892007-05-03 20:50:03 +02002657 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2658 num_dacs++;
2659 }
Matt Porter403d1942005-11-29 15:00:51 +01002660
Steve Longerbeam7b043892007-05-03 20:50:03 +02002661 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2662
Matt Porter403d1942005-11-29 15:00:51 +01002663 switch (cfg->line_outs) {
2664 case 3:
2665 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002666 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002667 cfg->line_out_pins[cfg->line_outs] =
2668 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002669 spec->line_switch = 1;
2670 cfg->line_outs++;
2671 }
2672 break;
2673 case 2:
2674 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002675 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002676 cfg->line_out_pins[cfg->line_outs] =
2677 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002678 spec->line_switch = 1;
2679 cfg->line_outs++;
2680 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002681 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002682 cfg->line_out_pins[cfg->line_outs] =
2683 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002684 spec->mic_switch = 1;
2685 cfg->line_outs++;
2686 }
2687 break;
2688 case 1:
2689 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002690 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002691 cfg->line_out_pins[cfg->line_outs] =
2692 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002693 spec->line_switch = 1;
2694 cfg->line_outs++;
2695 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002696 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002697 cfg->line_out_pins[cfg->line_outs] =
2698 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002699 spec->mic_switch = 1;
2700 cfg->line_outs++;
2701 }
2702 break;
2703 }
2704
2705 return 0;
2706}
2707
Steve Longerbeam7b043892007-05-03 20:50:03 +02002708
2709static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2710{
2711 int i;
2712
2713 for (i = 0; i < spec->multiout.num_dacs; i++) {
2714 if (spec->multiout.dac_nids[i] == nid)
2715 return 1;
2716 }
2717
2718 return 0;
2719}
2720
Matt Porter3cc08dc2006-01-23 15:27:49 +01002721/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002722 * Fill in the dac_nids table from the parsed pin configuration
2723 * This function only works when every pin in line_out_pins[]
2724 * contains atleast one DAC in its connection list. Some 92xx
2725 * codecs are not connected directly to a DAC, such as the 9200
2726 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002727 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002728static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002729 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002730{
2731 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002732 int i, j, conn_len = 0;
2733 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2734 unsigned int wcaps, wtype;
2735
Mattc7d4b2f2005-06-27 14:59:41 +02002736 for (i = 0; i < cfg->line_outs; i++) {
2737 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002738 conn_len = snd_hda_get_connections(codec, nid, conn,
2739 HDA_MAX_CONNECTIONS);
2740 for (j = 0; j < conn_len; j++) {
2741 wcaps = snd_hda_param_read(codec, conn[j],
2742 AC_PAR_AUDIO_WIDGET_CAP);
2743 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002744 if (wtype != AC_WID_AUD_OUT ||
2745 (wcaps & AC_WCAP_DIGITAL))
2746 continue;
2747 /* conn[j] is a DAC routed to this line-out */
2748 if (!is_in_dac_nids(spec, conn[j]))
2749 break;
2750 }
2751
2752 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002753 if (spec->multiout.num_dacs > 0) {
2754 /* we have already working output pins,
2755 * so let's drop the broken ones again
2756 */
2757 cfg->line_outs = spec->multiout.num_dacs;
2758 break;
2759 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002760 /* error out, no available DAC found */
2761 snd_printk(KERN_ERR
2762 "%s: No available DAC for pin 0x%x\n",
2763 __func__, nid);
2764 return -ENODEV;
2765 }
2766
2767 spec->multiout.dac_nids[i] = conn[j];
2768 spec->multiout.num_dacs++;
2769 if (conn_len > 1) {
2770 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002771 snd_hda_codec_write_cache(codec, nid, 0,
2772 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002773
2774 }
Mattc7d4b2f2005-06-27 14:59:41 +02002775 }
2776
Steve Longerbeam7b043892007-05-03 20:50:03 +02002777 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2778 spec->multiout.num_dacs,
2779 spec->multiout.dac_nids[0],
2780 spec->multiout.dac_nids[1],
2781 spec->multiout.dac_nids[2],
2782 spec->multiout.dac_nids[3],
2783 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002784 return 0;
2785}
2786
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002787/* create volume control/switch for the given prefx type */
2788static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2789{
2790 char name[32];
2791 int err;
2792
2793 sprintf(name, "%s Playback Volume", pfx);
2794 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2795 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2796 if (err < 0)
2797 return err;
2798 sprintf(name, "%s Playback Switch", pfx);
2799 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2800 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2801 if (err < 0)
2802 return err;
2803 return 0;
2804}
2805
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002806static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2807{
2808 if (!spec->multiout.hp_nid)
2809 spec->multiout.hp_nid = nid;
2810 else if (spec->multiout.num_dacs > 4) {
2811 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2812 return 1;
2813 } else {
2814 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2815 spec->multiout.num_dacs++;
2816 }
2817 return 0;
2818}
2819
2820static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2821{
2822 if (is_in_dac_nids(spec, nid))
2823 return 1;
2824 if (spec->multiout.hp_nid == nid)
2825 return 1;
2826 return 0;
2827}
2828
Mattc7d4b2f2005-06-27 14:59:41 +02002829/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002830static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002831 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002832{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002833 static const char *chname[4] = {
2834 "Front", "Surround", NULL /*CLFE*/, "Side"
2835 };
Matthew Ranostayd21995e2008-10-13 13:22:45 -04002836 hda_nid_t nid = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002837 int i, err;
2838
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002839 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002840 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002841
2842
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002843 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002844 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002845 continue;
2846
2847 nid = spec->multiout.dac_nids[i];
2848
2849 if (i == 2) {
2850 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002851 err = create_controls(spec, "Center", nid, 1);
2852 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002853 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002854 err = create_controls(spec, "LFE", nid, 2);
2855 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002856 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002857
2858 wid_caps = get_wcaps(codec, nid);
2859
2860 if (wid_caps & AC_WCAP_LR_SWAP) {
2861 err = stac92xx_add_control(spec,
2862 STAC_CTL_WIDGET_CLFE_SWITCH,
2863 "Swap Center/LFE Playback Switch", nid);
2864
2865 if (err < 0)
2866 return err;
2867 }
2868
Mattc7d4b2f2005-06-27 14:59:41 +02002869 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002870 err = create_controls(spec, chname[i], nid, 3);
2871 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002872 return err;
2873 }
2874 }
2875
Matthew Ranostayfedb7562008-09-23 21:46:30 -04002876 if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
2877 cfg->hp_outs && !spec->multiout.hp_nid)
2878 spec->multiout.hp_nid = nid;
2879
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002880 if (cfg->hp_outs > 1) {
2881 err = stac92xx_add_control(spec,
2882 STAC_CTL_WIDGET_HP_SWITCH,
Takashi Iwaid7a89432008-11-12 09:48:04 +01002883 "Headphone as Line Out Switch",
2884 cfg->hp_pins[cfg->hp_outs - 1]);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002885 if (err < 0)
2886 return err;
2887 }
2888
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002889 if (spec->line_switch) {
2890 nid = cfg->input_pins[AUTO_PIN_LINE];
2891 pincap = snd_hda_param_read(codec, nid,
2892 AC_PAR_PIN_CAP);
2893 if (pincap & AC_PINCAP_OUT) {
2894 err = stac92xx_add_control(spec,
2895 STAC_CTL_WIDGET_IO_SWITCH,
2896 "Line In as Output Switch", nid << 8);
2897 if (err < 0)
2898 return err;
2899 }
2900 }
Matt Porter403d1942005-11-29 15:00:51 +01002901
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002902 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002903 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002904 unsigned int mic_pin = AUTO_PIN_MIC;
2905again:
2906 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002907 def_conf = snd_hda_codec_read(codec, nid, 0,
2908 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002909 /* some laptops have an internal analog microphone
2910 * which can't be used as a output */
2911 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2912 pincap = snd_hda_param_read(codec, nid,
2913 AC_PAR_PIN_CAP);
2914 if (pincap & AC_PINCAP_OUT) {
2915 err = stac92xx_add_control(spec,
2916 STAC_CTL_WIDGET_IO_SWITCH,
2917 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002918 nid = snd_hda_codec_read(codec, nid, 0,
2919 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2920 if (!check_in_dac_nids(spec, nid))
2921 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002922 if (err < 0)
2923 return err;
2924 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002925 } else if (mic_pin == AUTO_PIN_MIC) {
2926 mic_pin = AUTO_PIN_FRONT_MIC;
2927 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002928 }
2929 }
Matt Porter403d1942005-11-29 15:00:51 +01002930
Mattc7d4b2f2005-06-27 14:59:41 +02002931 return 0;
2932}
2933
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002934/* add playback controls for Speaker and HP outputs */
2935static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2936 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002937{
2938 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002939 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002940 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002941
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002942 old_num_dacs = spec->multiout.num_dacs;
2943 for (i = 0; i < cfg->hp_outs; i++) {
2944 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2945 if (wid_caps & AC_WCAP_UNSOL_CAP)
2946 spec->hp_detect = 1;
2947 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2948 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2949 if (check_in_dac_nids(spec, nid))
2950 nid = 0;
2951 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002952 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002953 add_spec_dacs(spec, nid);
2954 }
2955 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002956 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002957 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2958 if (check_in_dac_nids(spec, nid))
2959 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002960 if (! nid)
2961 continue;
2962 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002963 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002964 for (i = 0; i < cfg->line_outs; i++) {
2965 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2966 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2967 if (check_in_dac_nids(spec, nid))
2968 nid = 0;
2969 if (! nid)
2970 continue;
2971 add_spec_dacs(spec, nid);
2972 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002973 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2974 static const char *pfxs[] = {
2975 "Speaker", "External Speaker", "Speaker2",
2976 };
2977 err = create_controls(spec, pfxs[i - old_num_dacs],
2978 spec->multiout.dac_nids[i], 3);
2979 if (err < 0)
2980 return err;
2981 }
2982 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002983 err = create_controls(spec, "Headphone",
2984 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002985 if (err < 0)
2986 return err;
2987 }
Mattc7d4b2f2005-06-27 14:59:41 +02002988
2989 return 0;
2990}
2991
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002992/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002993static const char *stac92xx_mono_labels[4] = {
2994 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002995};
2996
2997/* create mono mux for mono out on capable codecs */
2998static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2999{
3000 struct sigmatel_spec *spec = codec->spec;
3001 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
3002 int i, num_cons;
3003 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
3004
3005 num_cons = snd_hda_get_connections(codec,
3006 spec->mono_nid,
3007 con_lst,
3008 HDA_MAX_NUM_INPUTS);
3009 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
3010 return -EINVAL;
3011
3012 for (i = 0; i < num_cons; i++) {
3013 mono_mux->items[mono_mux->num_items].label =
3014 stac92xx_mono_labels[i];
3015 mono_mux->items[mono_mux->num_items].index = i;
3016 mono_mux->num_items++;
3017 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003018
3019 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
3020 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003021}
3022
Matthew Ranostay89385032008-09-11 09:49:39 -04003023/* labels for amp mux outputs */
3024static const char *stac92xx_amp_labels[3] = {
Matthew Ranostay4b33c762008-10-10 09:07:23 -04003025 "Front Microphone", "Microphone", "Line In",
Matthew Ranostay89385032008-09-11 09:49:39 -04003026};
3027
3028/* create amp out controls mux on capable codecs */
3029static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
3030{
3031 struct sigmatel_spec *spec = codec->spec;
3032 struct hda_input_mux *amp_mux = &spec->private_amp_mux;
3033 int i, err;
3034
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003035 for (i = 0; i < spec->num_amps; i++) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003036 amp_mux->items[amp_mux->num_items].label =
3037 stac92xx_amp_labels[i];
3038 amp_mux->items[amp_mux->num_items].index = i;
3039 amp_mux->num_items++;
3040 }
3041
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003042 if (spec->num_amps > 1) {
3043 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
3044 "Amp Selector Capture Switch", 0);
3045 if (err < 0)
3046 return err;
3047 }
Matthew Ranostay89385032008-09-11 09:49:39 -04003048 return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
3049 "Amp Capture Volume",
3050 HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
3051}
3052
3053
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003054/* create PC beep volume controls */
3055static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3056 hda_nid_t nid)
3057{
3058 struct sigmatel_spec *spec = codec->spec;
3059 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3060 int err;
3061
3062 /* check for mute support for the the amp */
3063 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3064 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3065 "PC Beep Playback Switch",
3066 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3067 if (err < 0)
3068 return err;
3069 }
3070
3071 /* check to see if there is volume support for the amp */
3072 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3073 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
3074 "PC Beep Playback Volume",
3075 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3076 if (err < 0)
3077 return err;
3078 }
3079 return 0;
3080}
3081
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003082#ifdef CONFIG_SND_HDA_INPUT_BEEP
3083#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
3084
3085static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
3086 struct snd_ctl_elem_value *ucontrol)
3087{
3088 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3089 ucontrol->value.integer.value[0] = codec->beep->enabled;
3090 return 0;
3091}
3092
3093static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
3094 struct snd_ctl_elem_value *ucontrol)
3095{
3096 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3097 int enabled = !!ucontrol->value.integer.value[0];
3098 if (codec->beep->enabled != enabled) {
3099 codec->beep->enabled = enabled;
3100 return 1;
3101 }
3102 return 0;
3103}
3104
3105static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
3106 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3107 .info = stac92xx_dig_beep_switch_info,
3108 .get = stac92xx_dig_beep_switch_get,
3109 .put = stac92xx_dig_beep_switch_put,
3110};
3111
3112static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
3113{
3114 return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
3115 0, "PC Beep Playback Switch", 0);
3116}
3117#endif
3118
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003119static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3120{
3121 struct sigmatel_spec *spec = codec->spec;
3122 int wcaps, nid, i, err = 0;
3123
3124 for (i = 0; i < spec->num_muxes; i++) {
3125 nid = spec->mux_nids[i];
3126 wcaps = get_wcaps(codec, nid);
3127
3128 if (wcaps & AC_WCAP_OUT_AMP) {
3129 err = stac92xx_add_control_idx(spec,
3130 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
3131 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3132 if (err < 0)
3133 return err;
3134 }
3135 }
3136 return 0;
3137};
3138
Matthew Ranostayd9737752008-09-07 12:03:41 +02003139static const char *stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04003140 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02003141};
3142
3143static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
3144{
3145 struct sigmatel_spec *spec = codec->spec;
3146 struct hda_input_mux *spdif_mux = &spec->private_smux;
Matthew Ranostay65973632008-09-16 10:39:37 -04003147 const char **labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003148 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04003149 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003150
3151 num_cons = snd_hda_get_connections(codec,
3152 spec->smux_nids[0],
3153 con_lst,
3154 HDA_MAX_NUM_INPUTS);
Matthew Ranostay65973632008-09-16 10:39:37 -04003155 if (!num_cons)
Matthew Ranostayd9737752008-09-07 12:03:41 +02003156 return -EINVAL;
3157
Matthew Ranostay65973632008-09-16 10:39:37 -04003158 if (!labels)
3159 labels = stac92xx_spdif_labels;
3160
Matthew Ranostayd9737752008-09-07 12:03:41 +02003161 for (i = 0; i < num_cons; i++) {
Matthew Ranostay65973632008-09-16 10:39:37 -04003162 spdif_mux->items[spdif_mux->num_items].label = labels[i];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003163 spdif_mux->items[spdif_mux->num_items].index = i;
3164 spdif_mux->num_items++;
3165 }
3166
3167 return 0;
3168}
3169
Matt Porter8b657272006-10-26 17:12:59 +02003170/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01003171static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02003172 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
3173 "Digital Mic 3", "Digital Mic 4"
3174};
3175
3176/* create playback/capture controls for input pins on dmic capable codecs */
3177static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3178 const struct auto_pin_cfg *cfg)
3179{
3180 struct sigmatel_spec *spec = codec->spec;
3181 struct hda_input_mux *dimux = &spec->private_dimux;
3182 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003183 int err, i, j;
3184 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02003185
3186 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
3187 dimux->items[dimux->num_items].index = 0;
3188 dimux->num_items++;
3189
3190 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003191 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02003192 int index;
3193 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003194 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02003195 unsigned int def_conf;
3196
3197 def_conf = snd_hda_codec_read(codec,
3198 spec->dmic_nids[i],
3199 0,
3200 AC_VERB_GET_CONFIG_DEFAULT,
3201 0);
3202 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
3203 continue;
3204
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003205 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02003206 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003207 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02003208 con_lst,
3209 HDA_MAX_NUM_INPUTS);
3210 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003211 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02003212 index = j;
3213 goto found;
3214 }
3215 continue;
3216found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003217 wcaps = get_wcaps(codec, nid) &
3218 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003219
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003220 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003221 sprintf(name, "%s Capture Volume",
3222 stac92xx_dmic_labels[dimux->num_items]);
3223
3224 err = stac92xx_add_control(spec,
3225 STAC_CTL_WIDGET_VOL,
3226 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003227 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3228 (wcaps & AC_WCAP_OUT_AMP) ?
3229 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003230 if (err < 0)
3231 return err;
3232 }
3233
Matt Porter8b657272006-10-26 17:12:59 +02003234 dimux->items[dimux->num_items].label =
3235 stac92xx_dmic_labels[dimux->num_items];
3236 dimux->items[dimux->num_items].index = index;
3237 dimux->num_items++;
3238 }
3239
3240 return 0;
3241}
3242
Mattc7d4b2f2005-06-27 14:59:41 +02003243/* create playback/capture controls for input pins */
3244static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3245{
3246 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003247 struct hda_input_mux *imux = &spec->private_imux;
3248 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3249 int i, j, k;
3250
3251 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003252 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003253
Takashi Iwai314634b2006-09-21 11:56:18 +02003254 if (!cfg->input_pins[i])
3255 continue;
3256 index = -1;
3257 for (j = 0; j < spec->num_muxes; j++) {
3258 int num_cons;
3259 num_cons = snd_hda_get_connections(codec,
3260 spec->mux_nids[j],
3261 con_lst,
3262 HDA_MAX_NUM_INPUTS);
3263 for (k = 0; k < num_cons; k++)
3264 if (con_lst[k] == cfg->input_pins[i]) {
3265 index = k;
3266 goto found;
3267 }
Mattc7d4b2f2005-06-27 14:59:41 +02003268 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003269 continue;
3270 found:
3271 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3272 imux->items[imux->num_items].index = index;
3273 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003274 }
3275
Steve Longerbeam7b043892007-05-03 20:50:03 +02003276 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003277 /*
3278 * Set the current input for the muxes.
3279 * The STAC9221 has two input muxes with identical source
3280 * NID lists. Hopefully this won't get confused.
3281 */
3282 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003283 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3284 AC_VERB_SET_CONNECT_SEL,
3285 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003286 }
3287 }
3288
Mattc7d4b2f2005-06-27 14:59:41 +02003289 return 0;
3290}
3291
Mattc7d4b2f2005-06-27 14:59:41 +02003292static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3293{
3294 struct sigmatel_spec *spec = codec->spec;
3295 int i;
3296
3297 for (i = 0; i < spec->autocfg.line_outs; i++) {
3298 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3299 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3300 }
3301}
3302
3303static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3304{
3305 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003306 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003307
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003308 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3309 hda_nid_t pin;
3310 pin = spec->autocfg.hp_pins[i];
3311 if (pin) /* connect to front */
3312 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3313 }
3314 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3315 hda_nid_t pin;
3316 pin = spec->autocfg.speaker_pins[i];
3317 if (pin) /* connect to front */
3318 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3319 }
Mattc7d4b2f2005-06-27 14:59:41 +02003320}
3321
Matt Porter3cc08dc2006-01-23 15:27:49 +01003322static 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 +02003323{
3324 struct sigmatel_spec *spec = codec->spec;
3325 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003326 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003327
Matt Porter8b657272006-10-26 17:12:59 +02003328 if ((err = snd_hda_parse_pin_def_config(codec,
3329 &spec->autocfg,
3330 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003331 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003332 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003333 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003334
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003335 /* If we have no real line-out pin and multiple hp-outs, HPs should
3336 * be set up as multi-channel outputs.
3337 */
3338 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3339 spec->autocfg.hp_outs > 1) {
3340 /* Copy hp_outs to line_outs, backup line_outs in
3341 * speaker_outs so that the following routines can handle
3342 * HP pins as primary outputs.
3343 */
3344 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3345 sizeof(spec->autocfg.line_out_pins));
3346 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3347 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3348 sizeof(spec->autocfg.hp_pins));
3349 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3350 hp_speaker_swap = 1;
3351 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003352 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003353 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3354 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003355 u32 caps = query_amp_caps(codec,
3356 spec->autocfg.mono_out_pin, dir);
3357 hda_nid_t conn_list[1];
3358
3359 /* get the mixer node and then the mono mux if it exists */
3360 if (snd_hda_get_connections(codec,
3361 spec->autocfg.mono_out_pin, conn_list, 1) &&
3362 snd_hda_get_connections(codec, conn_list[0],
3363 conn_list, 1)) {
3364
3365 int wcaps = get_wcaps(codec, conn_list[0]);
3366 int wid_type = (wcaps & AC_WCAP_TYPE)
3367 >> AC_WCAP_TYPE_SHIFT;
3368 /* LR swap check, some stac925x have a mux that
3369 * changes the DACs output path instead of the
3370 * mono-mux path.
3371 */
3372 if (wid_type == AC_WID_AUD_SEL &&
3373 !(wcaps & AC_WCAP_LR_SWAP))
3374 spec->mono_nid = conn_list[0];
3375 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003376 if (dir) {
3377 hda_nid_t nid = spec->autocfg.mono_out_pin;
3378
3379 /* most mono outs have a least a mute/unmute switch */
3380 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3381 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3382 "Mono Playback Switch",
3383 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003384 if (err < 0)
3385 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003386 /* check for volume support for the amp */
3387 if ((caps & AC_AMPCAP_NUM_STEPS)
3388 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3389 err = stac92xx_add_control(spec,
3390 STAC_CTL_WIDGET_VOL,
3391 "Mono Playback Volume",
3392 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3393 if (err < 0)
3394 return err;
3395 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003396 }
3397
3398 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3399 AC_PINCTL_OUT_EN);
3400 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003401
Matt Porter403d1942005-11-29 15:00:51 +01003402 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3403 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003404 if (spec->multiout.num_dacs == 0)
3405 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3406 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003407
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003408 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3409
3410 if (err < 0)
3411 return err;
3412
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003413 /* setup analog beep controls */
3414 if (spec->anabeep_nid > 0) {
3415 err = stac92xx_auto_create_beep_ctls(codec,
3416 spec->anabeep_nid);
3417 if (err < 0)
3418 return err;
3419 }
3420
3421 /* setup digital beep controls and input device */
3422#ifdef CONFIG_SND_HDA_INPUT_BEEP
3423 if (spec->digbeep_nid > 0) {
3424 hda_nid_t nid = spec->digbeep_nid;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003425 unsigned int caps;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003426
3427 err = stac92xx_auto_create_beep_ctls(codec, nid);
3428 if (err < 0)
3429 return err;
3430 err = snd_hda_attach_beep_device(codec, nid);
3431 if (err < 0)
3432 return err;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003433 /* if no beep switch is available, make its own one */
3434 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3435 if (codec->beep &&
3436 !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
3437 err = stac92xx_beep_switch_ctl(codec);
3438 if (err < 0)
3439 return err;
3440 }
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003441 }
3442#endif
3443
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003444 if (hp_speaker_swap == 1) {
3445 /* Restore the hp_outs and line_outs */
3446 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3447 sizeof(spec->autocfg.line_out_pins));
3448 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3449 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3450 sizeof(spec->autocfg.speaker_pins));
3451 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3452 memset(spec->autocfg.speaker_pins, 0,
3453 sizeof(spec->autocfg.speaker_pins));
3454 spec->autocfg.speaker_outs = 0;
3455 }
3456
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003457 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3458
3459 if (err < 0)
3460 return err;
3461
3462 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3463
3464 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003465 return err;
3466
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003467 if (spec->mono_nid > 0) {
3468 err = stac92xx_auto_create_mono_output_ctls(codec);
3469 if (err < 0)
3470 return err;
3471 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003472 if (spec->num_amps > 0) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003473 err = stac92xx_auto_create_amp_output_ctls(codec);
3474 if (err < 0)
3475 return err;
3476 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003477 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02003478 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3479 &spec->autocfg)) < 0)
3480 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003481 if (spec->num_muxes > 0) {
3482 err = stac92xx_auto_create_mux_input_ctls(codec);
3483 if (err < 0)
3484 return err;
3485 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003486 if (spec->num_smuxes > 0) {
3487 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3488 if (err < 0)
3489 return err;
3490 }
Matt Porter8b657272006-10-26 17:12:59 +02003491
Mattc7d4b2f2005-06-27 14:59:41 +02003492 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003493 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003494 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003495
Takashi Iwai82bc9552006-03-21 11:24:42 +01003496 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003497 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003498 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003499 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003500
3501 if (spec->kctl_alloc)
3502 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3503
3504 spec->input_mux = &spec->private_imux;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003505 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003506 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003507 spec->mono_mux = &spec->private_mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -04003508 spec->amp_mux = &spec->private_amp_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003509 return 1;
3510}
3511
Takashi Iwai82bc9552006-03-21 11:24:42 +01003512/* add playback controls for HP output */
3513static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3514 struct auto_pin_cfg *cfg)
3515{
3516 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003517 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003518 unsigned int wid_caps;
3519
3520 if (! pin)
3521 return 0;
3522
3523 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003524 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003525 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003526
3527 return 0;
3528}
3529
Richard Fish160ea0d2006-09-06 13:58:25 +02003530/* add playback controls for LFE output */
3531static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3532 struct auto_pin_cfg *cfg)
3533{
3534 struct sigmatel_spec *spec = codec->spec;
3535 int err;
3536 hda_nid_t lfe_pin = 0x0;
3537 int i;
3538
3539 /*
3540 * search speaker outs and line outs for a mono speaker pin
3541 * with an amp. If one is found, add LFE controls
3542 * for it.
3543 */
3544 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3545 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003546 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003547 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3548 if (wcaps == AC_WCAP_OUT_AMP)
3549 /* found a mono speaker with an amp, must be lfe */
3550 lfe_pin = pin;
3551 }
3552
3553 /* if speaker_outs is 0, then speakers may be in line_outs */
3554 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3555 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3556 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003557 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003558 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003559 AC_VERB_GET_CONFIG_DEFAULT,
3560 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003561 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003562 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003563 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3564 if (wcaps == AC_WCAP_OUT_AMP)
3565 /* found a mono speaker with an amp,
3566 must be lfe */
3567 lfe_pin = pin;
3568 }
3569 }
3570 }
3571
3572 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003573 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003574 if (err < 0)
3575 return err;
3576 }
3577
3578 return 0;
3579}
3580
Mattc7d4b2f2005-06-27 14:59:41 +02003581static int stac9200_parse_auto_config(struct hda_codec *codec)
3582{
3583 struct sigmatel_spec *spec = codec->spec;
3584 int err;
3585
Kailang Yangdf694da2005-12-05 19:42:22 +01003586 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003587 return err;
3588
3589 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3590 return err;
3591
Takashi Iwai82bc9552006-03-21 11:24:42 +01003592 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3593 return err;
3594
Richard Fish160ea0d2006-09-06 13:58:25 +02003595 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3596 return err;
3597
Takashi Iwai355a0ec2008-11-11 16:46:19 +01003598 if (spec->num_muxes > 0) {
3599 err = stac92xx_auto_create_mux_input_ctls(codec);
3600 if (err < 0)
3601 return err;
3602 }
3603
Takashi Iwai82bc9552006-03-21 11:24:42 +01003604 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003605 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003606 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003607 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003608
3609 if (spec->kctl_alloc)
3610 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3611
3612 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003613 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003614
3615 return 1;
3616}
3617
Sam Revitch62fe78e2006-05-10 15:09:17 +02003618/*
3619 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3620 * funky external mute control using GPIO pins.
3621 */
3622
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003623static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003624 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003625{
3626 unsigned int gpiostate, gpiomask, gpiodir;
3627
3628 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3629 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003630 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003631
3632 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3633 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003634 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003635
3636 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3637 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003638 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003639
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003640 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003641 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3642
3643 snd_hda_codec_write(codec, codec->afg, 0,
3644 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003645 snd_hda_codec_read(codec, codec->afg, 0,
3646 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003647
3648 msleep(1);
3649
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003650 snd_hda_codec_read(codec, codec->afg, 0,
3651 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003652}
3653
Takashi Iwai314634b2006-09-21 11:56:18 +02003654static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3655 unsigned int event)
3656{
3657 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003658 snd_hda_codec_write_cache(codec, nid, 0,
3659 AC_VERB_SET_UNSOLICITED_ENABLE,
3660 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003661}
3662
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003663static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3664{
3665 int i;
3666 for (i = 0; i < cfg->hp_outs; i++)
3667 if (cfg->hp_pins[i] == nid)
3668 return 1; /* nid is a HP-Out */
3669
3670 return 0; /* nid is not a HP-Out */
3671};
3672
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003673static void stac92xx_power_down(struct hda_codec *codec)
3674{
3675 struct sigmatel_spec *spec = codec->spec;
3676
3677 /* power down inactive DACs */
3678 hda_nid_t *dac;
3679 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003680 if (!is_in_dac_nids(spec, *dac) &&
3681 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003682 snd_hda_codec_write_cache(codec, *dac, 0,
3683 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3684}
3685
Mattc7d4b2f2005-06-27 14:59:41 +02003686static int stac92xx_init(struct hda_codec *codec)
3687{
3688 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003689 struct auto_pin_cfg *cfg = &spec->autocfg;
3690 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003691
Mattc7d4b2f2005-06-27 14:59:41 +02003692 snd_hda_sequence_write(codec, spec->init);
3693
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003694 /* power down adcs initially */
3695 if (spec->powerdown_adcs)
3696 for (i = 0; i < spec->num_adcs; i++)
3697 snd_hda_codec_write_cache(codec,
3698 spec->adc_nids[i], 0,
3699 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003700 /* set up pins */
3701 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003702 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003703 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003704 enable_pin_detect(codec, cfg->hp_pins[i],
3705 STAC_HP_EVENT);
Takashi Iwai0a07aca2007-03-13 10:40:23 +01003706 /* force to enable the first line-out; the others are set up
3707 * in unsol_event
3708 */
3709 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3710 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003711 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003712 /* fake event to set up pins */
3713 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3714 } else {
3715 stac92xx_auto_init_multi_out(codec);
3716 stac92xx_auto_init_hp_out(codec);
3717 }
3718 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003719 hda_nid_t nid = cfg->input_pins[i];
3720 if (nid) {
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01003721 unsigned int pinctl;
3722 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
3723 /* for mic pins, force to initialize */
3724 pinctl = stac92xx_get_vref(codec, nid);
3725 } else {
3726 pinctl = snd_hda_codec_read(codec, nid, 0,
3727 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3728 /* if PINCTL already set then skip */
3729 if (pinctl & AC_PINCTL_IN_EN)
3730 continue;
3731 }
3732 pinctl |= AC_PINCTL_IN_EN;
Takashi Iwaic960a032006-03-23 17:06:28 +01003733 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3734 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003735 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003736 for (i = 0; i < spec->num_dmics; i++)
3737 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3738 AC_PINCTL_IN_EN);
3739 for (i = 0; i < spec->num_pwrs; i++) {
3740 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3741 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3742 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3743 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003744 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3745 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003746 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003747 /* outputs are only ports capable of power management
3748 * any attempts on powering down a input port cause the
3749 * referenced VREF to act quirky.
3750 */
3751 if (pinctl & AC_PINCTL_IN_EN)
3752 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003753 /* skip any ports that don't have jacks since presence
3754 * detection is useless */
3755 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003756 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003757 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3758 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3759 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003760 if (spec->dac_list)
3761 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003762 if (cfg->dig_out_pin)
3763 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3764 AC_PINCTL_OUT_EN);
3765 if (cfg->dig_in_pin)
3766 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3767 AC_PINCTL_IN_EN);
3768
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003769 stac_gpio_set(codec, spec->gpio_mask,
3770 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003771
Mattc7d4b2f2005-06-27 14:59:41 +02003772 return 0;
3773}
3774
Matt2f2f4252005-04-13 14:45:30 +02003775static void stac92xx_free(struct hda_codec *codec)
3776{
Mattc7d4b2f2005-06-27 14:59:41 +02003777 struct sigmatel_spec *spec = codec->spec;
3778 int i;
3779
3780 if (! spec)
3781 return;
3782
3783 if (spec->kctl_alloc) {
3784 for (i = 0; i < spec->num_kctl_used; i++)
3785 kfree(spec->kctl_alloc[i].name);
3786 kfree(spec->kctl_alloc);
3787 }
3788
Richard Fish11b44bb2006-08-23 18:31:34 +02003789 if (spec->bios_pin_configs)
3790 kfree(spec->bios_pin_configs);
3791
Mattc7d4b2f2005-06-27 14:59:41 +02003792 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003793 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003794}
3795
Matt4e550962005-07-04 17:51:39 +02003796static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3797 unsigned int flag)
3798{
3799 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3800 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003801
Takashi Iwaif9acba42007-05-29 18:01:06 +02003802 if (pin_ctl & AC_PINCTL_IN_EN) {
3803 /*
3804 * we need to check the current set-up direction of
3805 * shared input pins since they can be switched via
3806 * "xxx as Output" mixer switch
3807 */
3808 struct sigmatel_spec *spec = codec->spec;
3809 struct auto_pin_cfg *cfg = &spec->autocfg;
3810 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3811 spec->line_switch) ||
3812 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3813 spec->mic_switch))
3814 return;
3815 }
3816
Steve Longerbeam7b043892007-05-03 20:50:03 +02003817 /* if setting pin direction bits, clear the current
3818 direction bits first */
3819 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3820 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3821
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003822 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003823 AC_VERB_SET_PIN_WIDGET_CONTROL,
3824 pin_ctl | flag);
3825}
3826
3827static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3828 unsigned int flag)
3829{
3830 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3831 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003832 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003833 AC_VERB_SET_PIN_WIDGET_CONTROL,
3834 pin_ctl & ~flag);
3835}
3836
Jiang Zhe40c1d302007-11-12 13:05:16 +01003837static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003838{
3839 if (!nid)
3840 return 0;
3841 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003842 & (1 << 31)) {
3843 unsigned int pinctl;
3844 pinctl = snd_hda_codec_read(codec, nid, 0,
3845 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3846 if (pinctl & AC_PINCTL_IN_EN)
3847 return 0; /* mic- or line-input */
3848 else
3849 return 1; /* HP-output */
3850 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003851 return 0;
3852}
3853
Takashi Iwaid7a89432008-11-12 09:48:04 +01003854/* return non-zero if the hp-pin of the given array index isn't
3855 * a jack-detection target
3856 */
3857static int no_hp_sensing(struct sigmatel_spec *spec, int i)
3858{
3859 struct auto_pin_cfg *cfg = &spec->autocfg;
3860
3861 /* ignore sensing of shared line and mic jacks */
3862 if (spec->line_switch &&
3863 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
3864 return 1;
3865 if (spec->mic_switch &&
3866 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
3867 return 1;
3868 /* ignore if the pin is set as line-out */
3869 if (cfg->hp_pins[i] == spec->hp_switch)
3870 return 1;
3871 return 0;
3872}
3873
Takashi Iwai314634b2006-09-21 11:56:18 +02003874static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003875{
3876 struct sigmatel_spec *spec = codec->spec;
3877 struct auto_pin_cfg *cfg = &spec->autocfg;
3878 int i, presence;
3879
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003880 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003881 if (spec->gpio_mute)
3882 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3883 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3884
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003885 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003886 if (presence)
3887 break;
Takashi Iwaid7a89432008-11-12 09:48:04 +01003888 if (no_hp_sensing(spec, i))
3889 continue;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003890 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003891 }
Matt4e550962005-07-04 17:51:39 +02003892
3893 if (presence) {
Takashi Iwaid7a89432008-11-12 09:48:04 +01003894 /* disable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003895 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01003896 stac92xx_reset_pinctl(codec, spec->hp_switch,
3897 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003898 for (i = 0; i < cfg->line_outs; i++)
3899 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3900 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003901 for (i = 0; i < cfg->speaker_outs; i++)
3902 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3903 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003904 if (spec->eapd_mask)
3905 stac_gpio_set(codec, spec->gpio_mask,
3906 spec->gpio_dir, spec->gpio_data &
3907 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003908 } else {
Takashi Iwaid7a89432008-11-12 09:48:04 +01003909 /* enable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003910 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01003911 stac92xx_set_pinctl(codec, spec->hp_switch,
3912 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003913 for (i = 0; i < cfg->line_outs; i++)
3914 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3915 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003916 for (i = 0; i < cfg->speaker_outs; i++)
3917 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3918 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003919 if (spec->eapd_mask)
3920 stac_gpio_set(codec, spec->gpio_mask,
3921 spec->gpio_dir, spec->gpio_data |
3922 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003923 }
Takashi Iwaid7a89432008-11-12 09:48:04 +01003924 /* toggle hp outs */
3925 for (i = 0; i < cfg->hp_outs; i++) {
3926 unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
3927 if (no_hp_sensing(spec, i))
3928 continue;
3929 if (presence)
3930 stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
3931 else
3932 stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
3933 }
Matt4e550962005-07-04 17:51:39 +02003934}
3935
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003936static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3937{
3938 struct sigmatel_spec *spec = codec->spec;
3939 hda_nid_t nid = spec->pwr_nids[idx];
3940 int presence, val;
3941 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3942 & 0x000000ff;
3943 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003944
3945 /* several codecs have two power down bits */
3946 if (spec->pwr_mapping)
3947 idx = spec->pwr_mapping[idx];
3948 else
3949 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003950
3951 if (presence)
3952 val &= ~idx;
3953 else
3954 val |= idx;
3955
3956 /* power down unused output ports */
3957 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3958};
3959
Takashi Iwai314634b2006-09-21 11:56:18 +02003960static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3961{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003962 struct sigmatel_spec *spec = codec->spec;
3963 int idx = res >> 26 & 0x0f;
3964
Matthew Ranostay72474be2008-10-09 09:32:17 -04003965 switch ((res >> 26) & 0x70) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003966 case STAC_HP_EVENT:
3967 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003968 /* fallthru */
3969 case STAC_PWR_EVENT:
3970 if (spec->num_pwrs > 0)
3971 stac92xx_pin_sense(codec, idx);
Matthew Ranostay72474be2008-10-09 09:32:17 -04003972 break;
3973 case STAC_VREF_EVENT: {
3974 int data = snd_hda_codec_read(codec, codec->afg, 0,
3975 AC_VERB_GET_GPIO_DATA, 0);
3976 /* toggle VREF state based on GPIOx status */
3977 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
3978 !!(data & (1 << idx)));
3979 break;
3980 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003981 }
3982}
3983
Takashi Iwaicb53c622007-08-10 17:21:45 +02003984#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003985static int stac92xx_resume(struct hda_codec *codec)
3986{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003987 struct sigmatel_spec *spec = codec->spec;
3988
Richard Fish11b44bb2006-08-23 18:31:34 +02003989 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003990 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003991 stac_gpio_set(codec, spec->gpio_mask,
3992 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003993 snd_hda_codec_resume_amp(codec);
3994 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003995 /* power down inactive DACs */
3996 if (spec->dac_list)
3997 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003998 /* invoke unsolicited event to reset the HP state */
3999 if (spec->hp_detect)
4000 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02004001 return 0;
4002}
4003#endif
4004
Matt2f2f4252005-04-13 14:45:30 +02004005static struct hda_codec_ops stac92xx_patch_ops = {
4006 .build_controls = stac92xx_build_controls,
4007 .build_pcms = stac92xx_build_pcms,
4008 .init = stac92xx_init,
4009 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02004010 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004011#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004012 .resume = stac92xx_resume,
4013#endif
Matt2f2f4252005-04-13 14:45:30 +02004014};
4015
4016static int patch_stac9200(struct hda_codec *codec)
4017{
4018 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004019 int err;
Matt2f2f4252005-04-13 14:45:30 +02004020
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004021 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004022 if (spec == NULL)
4023 return -ENOMEM;
4024
4025 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004026 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004027 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004028 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
4029 stac9200_models,
4030 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02004031 if (spec->board_config < 0) {
4032 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
4033 err = stac92xx_save_bios_config_regs(codec);
4034 if (err < 0) {
4035 stac92xx_free(codec);
4036 return err;
4037 }
4038 spec->pin_configs = spec->bios_pin_configs;
4039 } else {
Matt Porter403d1942005-11-29 15:00:51 +01004040 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
4041 stac92xx_set_config_regs(codec);
4042 }
Matt2f2f4252005-04-13 14:45:30 +02004043
4044 spec->multiout.max_channels = 2;
4045 spec->multiout.num_dacs = 1;
4046 spec->multiout.dac_nids = stac9200_dac_nids;
4047 spec->adc_nids = stac9200_adc_nids;
4048 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02004049 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02004050 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004051 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004052 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004053
Tobin Davisbf277782008-02-03 20:31:47 +01004054 if (spec->board_config == STAC_9200_GATEWAY ||
4055 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02004056 spec->init = stac9200_eapd_init;
4057 else
4058 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004059 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004060
Takashi Iwai117f2572008-03-18 09:53:23 +01004061 if (spec->board_config == STAC_9200_PANASONIC) {
4062 spec->gpio_mask = spec->gpio_dir = 0x09;
4063 spec->gpio_data = 0x00;
4064 }
4065
Mattc7d4b2f2005-06-27 14:59:41 +02004066 err = stac9200_parse_auto_config(codec);
4067 if (err < 0) {
4068 stac92xx_free(codec);
4069 return err;
4070 }
Matt2f2f4252005-04-13 14:45:30 +02004071
4072 codec->patch_ops = stac92xx_patch_ops;
4073
4074 return 0;
4075}
4076
Tobin Davis8e21c342007-01-08 11:04:17 +01004077static int patch_stac925x(struct hda_codec *codec)
4078{
4079 struct sigmatel_spec *spec;
4080 int err;
4081
4082 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4083 if (spec == NULL)
4084 return -ENOMEM;
4085
4086 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004087 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01004088 spec->pin_nids = stac925x_pin_nids;
4089 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
4090 stac925x_models,
4091 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004092 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01004093 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02004094 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
4095 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01004096 err = stac92xx_save_bios_config_regs(codec);
4097 if (err < 0) {
4098 stac92xx_free(codec);
4099 return err;
4100 }
4101 spec->pin_configs = spec->bios_pin_configs;
4102 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
4103 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
4104 stac92xx_set_config_regs(codec);
4105 }
4106
4107 spec->multiout.max_channels = 2;
4108 spec->multiout.num_dacs = 1;
4109 spec->multiout.dac_nids = stac925x_dac_nids;
4110 spec->adc_nids = stac925x_adc_nids;
4111 spec->mux_nids = stac925x_mux_nids;
4112 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004113 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004114 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02004115 switch (codec->vendor_id) {
4116 case 0x83847632: /* STAC9202 */
4117 case 0x83847633: /* STAC9202D */
4118 case 0x83847636: /* STAC9251 */
4119 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02004120 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02004121 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01004122 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
4123 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02004124 break;
4125 default:
4126 spec->num_dmics = 0;
4127 break;
4128 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004129
4130 spec->init = stac925x_core_init;
4131 spec->mixer = stac925x_mixer;
4132
4133 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004134 if (!err) {
4135 if (spec->board_config < 0) {
4136 printk(KERN_WARNING "hda_codec: No auto-config is "
4137 "available, default to model=ref\n");
4138 spec->board_config = STAC_925x_REF;
4139 goto again;
4140 }
4141 err = -EINVAL;
4142 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004143 if (err < 0) {
4144 stac92xx_free(codec);
4145 return err;
4146 }
4147
4148 codec->patch_ops = stac92xx_patch_ops;
4149
4150 return 0;
4151}
4152
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004153static struct hda_input_mux stac92hd73xx_dmux = {
4154 .num_items = 4,
4155 .items = {
4156 { "Analog Inputs", 0x0b },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004157 { "Digital Mic 1", 0x09 },
4158 { "Digital Mic 2", 0x0a },
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004159 { "CD", 0x08 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004160 }
4161};
4162
4163static int patch_stac92hd73xx(struct hda_codec *codec)
4164{
4165 struct sigmatel_spec *spec;
4166 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
4167 int err = 0;
4168
4169 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4170 if (spec == NULL)
4171 return -ENOMEM;
4172
4173 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02004174 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004175 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
4176 spec->pin_nids = stac92hd73xx_pin_nids;
4177 spec->board_config = snd_hda_check_board_config(codec,
4178 STAC_92HD73XX_MODELS,
4179 stac92hd73xx_models,
4180 stac92hd73xx_cfg_tbl);
4181again:
4182 if (spec->board_config < 0) {
4183 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4184 " STAC92HD73XX, using BIOS defaults\n");
4185 err = stac92xx_save_bios_config_regs(codec);
4186 if (err < 0) {
4187 stac92xx_free(codec);
4188 return err;
4189 }
4190 spec->pin_configs = spec->bios_pin_configs;
4191 } else {
4192 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
4193 stac92xx_set_config_regs(codec);
4194 }
4195
4196 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
4197 conn, STAC92HD73_DAC_COUNT + 2) - 1;
4198
4199 if (spec->multiout.num_dacs < 0) {
4200 printk(KERN_WARNING "hda_codec: Could not determine "
4201 "number of channels defaulting to DAC count\n");
4202 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
4203 }
4204
4205 switch (spec->multiout.num_dacs) {
4206 case 0x3: /* 6 Channel */
4207 spec->mixer = stac92hd73xx_6ch_mixer;
4208 spec->init = stac92hd73xx_6ch_core_init;
4209 break;
4210 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004211 spec->mixer = stac92hd73xx_8ch_mixer;
4212 spec->init = stac92hd73xx_8ch_core_init;
4213 break;
4214 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004215 spec->mixer = stac92hd73xx_10ch_mixer;
4216 spec->init = stac92hd73xx_10ch_core_init;
4217 };
4218
4219 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
4220 spec->aloopback_mask = 0x01;
4221 spec->aloopback_shift = 8;
4222
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004223 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004224 spec->mux_nids = stac92hd73xx_mux_nids;
4225 spec->adc_nids = stac92hd73xx_adc_nids;
4226 spec->dmic_nids = stac92hd73xx_dmic_nids;
4227 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004228 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostay89385032008-09-11 09:49:39 -04004229 spec->amp_nids = stac92hd73xx_amp_nids;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004230 spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004231
4232 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
4233 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai16970552007-12-18 18:05:52 +01004234 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004235 memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
4236 sizeof(stac92hd73xx_dmux));
4237
Matthew Ranostaya7662642008-02-21 07:51:14 +01004238 switch (spec->board_config) {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004239 case STAC_DELL_EQ:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004240 spec->init = dell_eq_core_init;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004241 /* fallthru */
4242 case STAC_DELL_M6:
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004243 spec->num_smuxes = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004244 spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
4245 spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
4246 spec->num_amps = 1;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004247
4248 if (!spec->init)
4249 spec->init = dell_m6_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004250 switch (codec->subsystem_id) {
4251 case 0x1028025e: /* Analog Mics */
4252 case 0x1028025f:
4253 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4254 spec->num_dmics = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004255 spec->private_dimux.num_items = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004256 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01004257 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004258 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004259 case 0x10280254:
4260 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01004261 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4262 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004263 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004264 break;
4265 case 0x10280256: /* Both */
4266 case 0x10280057:
4267 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4268 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4269 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004270 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004271 break;
4272 }
4273 break;
4274 default:
4275 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004276 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaya7662642008-02-21 07:51:14 +01004277 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004278 if (spec->board_config > STAC_92HD73XX_REF) {
4279 /* GPIO0 High = Enable EAPD */
4280 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
4281 spec->gpio_data = 0x01;
4282 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004283 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004284
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004285 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
4286 spec->pwr_nids = stac92hd73xx_pwr_nids;
4287
Matthew Ranostayd9737752008-09-07 12:03:41 +02004288 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004289
4290 if (!err) {
4291 if (spec->board_config < 0) {
4292 printk(KERN_WARNING "hda_codec: No auto-config is "
4293 "available, default to model=ref\n");
4294 spec->board_config = STAC_92HD73XX_REF;
4295 goto again;
4296 }
4297 err = -EINVAL;
4298 }
4299
4300 if (err < 0) {
4301 stac92xx_free(codec);
4302 return err;
4303 }
4304
4305 codec->patch_ops = stac92xx_patch_ops;
4306
4307 return 0;
4308}
4309
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004310static struct hda_input_mux stac92hd83xxx_dmux = {
4311 .num_items = 3,
4312 .items = {
4313 { "Analog Inputs", 0x03 },
4314 { "Digital Mic 1", 0x04 },
4315 { "Digital Mic 2", 0x05 },
4316 }
4317};
4318
4319static int patch_stac92hd83xxx(struct hda_codec *codec)
4320{
4321 struct sigmatel_spec *spec;
4322 int err;
4323
4324 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4325 if (spec == NULL)
4326 return -ENOMEM;
4327
4328 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004329 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004330 spec->mono_nid = 0x19;
4331 spec->digbeep_nid = 0x21;
4332 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4333 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4334 spec->adc_nids = stac92hd83xxx_adc_nids;
4335 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4336 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4337 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4338 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4339
4340 spec->init = stac92hd83xxx_core_init;
4341 switch (codec->vendor_id) {
4342 case 0x111d7605:
4343 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4344 break;
4345 default:
4346 spec->num_pwrs--;
4347 spec->init++; /* switch to config #2 */
4348 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4349 }
4350
4351 spec->mixer = stac92hd83xxx_mixer;
4352 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4353 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4354 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4355 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4356 spec->dinput_mux = &stac92hd83xxx_dmux;
4357 spec->pin_nids = stac92hd83xxx_pin_nids;
4358 spec->board_config = snd_hda_check_board_config(codec,
4359 STAC_92HD83XXX_MODELS,
4360 stac92hd83xxx_models,
4361 stac92hd83xxx_cfg_tbl);
4362again:
4363 if (spec->board_config < 0) {
4364 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4365 " STAC92HD83XXX, using BIOS defaults\n");
4366 err = stac92xx_save_bios_config_regs(codec);
4367 if (err < 0) {
4368 stac92xx_free(codec);
4369 return err;
4370 }
4371 spec->pin_configs = spec->bios_pin_configs;
4372 } else {
4373 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4374 stac92xx_set_config_regs(codec);
4375 }
4376
4377 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4378 if (!err) {
4379 if (spec->board_config < 0) {
4380 printk(KERN_WARNING "hda_codec: No auto-config is "
4381 "available, default to model=ref\n");
4382 spec->board_config = STAC_92HD83XXX_REF;
4383 goto again;
4384 }
4385 err = -EINVAL;
4386 }
4387
4388 if (err < 0) {
4389 stac92xx_free(codec);
4390 return err;
4391 }
4392
4393 codec->patch_ops = stac92xx_patch_ops;
4394
4395 return 0;
4396}
4397
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004398#ifdef SND_HDA_NEEDS_RESUME
4399static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4400{
4401 struct sigmatel_spec *spec = codec->spec;
4402 int i;
4403 snd_hda_codec_write_cache(codec, codec->afg, 0,
4404 AC_VERB_SET_POWER_STATE, pwr);
4405
4406 msleep(1);
4407 for (i = 0; i < spec->num_adcs; i++) {
4408 snd_hda_codec_write_cache(codec,
4409 spec->adc_nids[i], 0,
4410 AC_VERB_SET_POWER_STATE, pwr);
4411 }
4412};
4413
4414static int stac92hd71xx_resume(struct hda_codec *codec)
4415{
4416 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4417 return stac92xx_resume(codec);
4418}
4419
4420static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4421{
4422 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4423 return 0;
4424};
4425
4426#endif
4427
4428static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4429 .build_controls = stac92xx_build_controls,
4430 .build_pcms = stac92xx_build_pcms,
4431 .init = stac92xx_init,
4432 .free = stac92xx_free,
4433 .unsol_event = stac92xx_unsol_event,
4434#ifdef SND_HDA_NEEDS_RESUME
4435 .resume = stac92hd71xx_resume,
4436 .suspend = stac92hd71xx_suspend,
4437#endif
4438};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004439
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004440static struct hda_input_mux stac92hd71bxx_dmux = {
4441 .num_items = 4,
4442 .items = {
4443 { "Analog Inputs", 0x00 },
4444 { "Mixer", 0x01 },
4445 { "Digital Mic 1", 0x02 },
4446 { "Digital Mic 2", 0x03 },
4447 }
4448};
4449
Matthew Ranostaye035b842007-11-06 11:53:55 +01004450static int patch_stac92hd71bxx(struct hda_codec *codec)
4451{
4452 struct sigmatel_spec *spec;
4453 int err = 0;
4454
4455 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4456 if (spec == NULL)
4457 return -ENOMEM;
4458
4459 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004460 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004461 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004462 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004463 spec->pin_nids = stac92hd71bxx_pin_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004464 memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
4465 sizeof(stac92hd71bxx_dmux));
Matthew Ranostaye035b842007-11-06 11:53:55 +01004466 spec->board_config = snd_hda_check_board_config(codec,
4467 STAC_92HD71BXX_MODELS,
4468 stac92hd71bxx_models,
4469 stac92hd71bxx_cfg_tbl);
4470again:
4471 if (spec->board_config < 0) {
4472 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4473 " STAC92HD71BXX, using BIOS defaults\n");
4474 err = stac92xx_save_bios_config_regs(codec);
4475 if (err < 0) {
4476 stac92xx_free(codec);
4477 return err;
4478 }
4479 spec->pin_configs = spec->bios_pin_configs;
4480 } else {
4481 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4482 stac92xx_set_config_regs(codec);
4483 }
4484
Takashi Iwai41c3b642008-11-18 10:45:15 +01004485 if (spec->board_config > STAC_92HD71BXX_REF) {
4486 /* GPIO0 = EAPD */
4487 spec->gpio_mask = 0x01;
4488 spec->gpio_dir = 0x01;
4489 spec->gpio_data = 0x01;
4490 }
4491
Matthew Ranostay541eee82007-12-14 12:08:04 +01004492 switch (codec->vendor_id) {
4493 case 0x111d76b6: /* 4 Port without Analog Mixer */
4494 case 0x111d76b7:
4495 case 0x111d76b4: /* 6 Port without Analog Mixer */
4496 case 0x111d76b5:
4497 spec->mixer = stac92hd71bxx_mixer;
4498 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004499 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004500 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004501 case 0x111d7608: /* 5 Port with Analog Mixer */
Takashi Iwai8e5f2622008-11-15 19:28:54 +01004502 switch (spec->board_config) {
4503 case STAC_HP_M4:
Matthew Ranostay72474be2008-10-09 09:32:17 -04004504 /* Enable VREF power saving on GPIO1 detect */
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01004505 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay72474be2008-10-09 09:32:17 -04004506 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4507 snd_hda_codec_write_cache(codec, codec->afg, 0,
4508 AC_VERB_SET_UNSOLICITED_ENABLE,
4509 (AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
4510 spec->gpio_mask |= 0x02;
4511 break;
4512 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004513 if ((codec->revision_id & 0xf) == 0 ||
4514 (codec->revision_id & 0xf) == 1) {
4515#ifdef SND_HDA_NEEDS_RESUME
4516 codec->patch_ops = stac92hd71bxx_patch_ops;
4517#endif
4518 spec->stream_delay = 40; /* 40 milliseconds */
4519 }
4520
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004521 /* no output amps */
4522 spec->num_pwrs = 0;
4523 spec->mixer = stac92hd71bxx_analog_mixer;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004524 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004525
4526 /* disable VSW */
4527 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4528 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4529 break;
4530 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004531 if ((codec->revision_id & 0xf) == 1) {
4532#ifdef SND_HDA_NEEDS_RESUME
4533 codec->patch_ops = stac92hd71bxx_patch_ops;
4534#endif
4535 spec->stream_delay = 40; /* 40 milliseconds */
4536 }
4537
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004538 /* no output amps */
4539 spec->num_pwrs = 0;
4540 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004541 default:
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004542 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004543 spec->mixer = stac92hd71bxx_analog_mixer;
4544 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004545 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004546 }
4547
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004548 spec->aloopback_mask = 0x50;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004549 spec->aloopback_shift = 0;
4550
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004551 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004552 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004553 spec->mux_nids = stac92hd71bxx_mux_nids;
4554 spec->adc_nids = stac92hd71bxx_adc_nids;
4555 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004556 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004557 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004558 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004559
4560 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4561 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004562
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004563 switch (spec->board_config) {
4564 case STAC_HP_M4:
4565 spec->num_dmics = 0;
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004566 spec->num_smuxes = 0;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004567 spec->num_dmuxes = 0;
4568
4569 /* enable internal microphone */
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004570 stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
4571 stac92xx_auto_set_pinctl(codec, 0x0e,
4572 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004573 break;
4574 default:
4575 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4576 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4577 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4578 };
4579
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004580 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004581 spec->multiout.hp_nid = 0x11;
4582 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004583 if (spec->dinput_mux)
4584 spec->private_dimux.num_items +=
4585 spec->num_dmics -
4586 (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004587
4588 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4589 if (!err) {
4590 if (spec->board_config < 0) {
4591 printk(KERN_WARNING "hda_codec: No auto-config is "
4592 "available, default to model=ref\n");
4593 spec->board_config = STAC_92HD71BXX_REF;
4594 goto again;
4595 }
4596 err = -EINVAL;
4597 }
4598
4599 if (err < 0) {
4600 stac92xx_free(codec);
4601 return err;
4602 }
4603
Matthew Ranostaye035b842007-11-06 11:53:55 +01004604 return 0;
4605};
4606
Matt2f2f4252005-04-13 14:45:30 +02004607static int patch_stac922x(struct hda_codec *codec)
4608{
4609 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004610 int err;
Matt2f2f4252005-04-13 14:45:30 +02004611
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004612 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004613 if (spec == NULL)
4614 return -ENOMEM;
4615
4616 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004617 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004618 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004619 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4620 stac922x_models,
4621 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004622 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004623 spec->gpio_mask = spec->gpio_dir = 0x03;
4624 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004625 /* Intel Macs have all same PCI SSID, so we need to check
4626 * codec SSID to distinguish the exact models
4627 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004628 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004629 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004630
4631 case 0x106b0800:
4632 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004633 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004634 case 0x106b0600:
4635 case 0x106b0700:
4636 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004637 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004638 case 0x106b0e00:
4639 case 0x106b0f00:
4640 case 0x106b1600:
4641 case 0x106b1700:
4642 case 0x106b0200:
4643 case 0x106b1e00:
4644 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004645 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004646 case 0x106b1a00:
4647 case 0x00000100:
4648 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004649 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004650 case 0x106b0a00:
4651 case 0x106b2200:
4652 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004653 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004654 default:
4655 spec->board_config = STAC_INTEL_MAC_V3;
4656 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004657 }
4658 }
4659
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004660 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004661 if (spec->board_config < 0) {
4662 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4663 "using BIOS defaults\n");
4664 err = stac92xx_save_bios_config_regs(codec);
4665 if (err < 0) {
4666 stac92xx_free(codec);
4667 return err;
4668 }
4669 spec->pin_configs = spec->bios_pin_configs;
4670 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004671 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4672 stac92xx_set_config_regs(codec);
4673 }
Matt2f2f4252005-04-13 14:45:30 +02004674
Matt2f2f4252005-04-13 14:45:30 +02004675 spec->adc_nids = stac922x_adc_nids;
4676 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004677 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004678 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004679 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004680 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004681
4682 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004683 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004684
4685 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004686
Matt Porter3cc08dc2006-01-23 15:27:49 +01004687 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004688 if (!err) {
4689 if (spec->board_config < 0) {
4690 printk(KERN_WARNING "hda_codec: No auto-config is "
4691 "available, default to model=ref\n");
4692 spec->board_config = STAC_D945_REF;
4693 goto again;
4694 }
4695 err = -EINVAL;
4696 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004697 if (err < 0) {
4698 stac92xx_free(codec);
4699 return err;
4700 }
4701
4702 codec->patch_ops = stac92xx_patch_ops;
4703
Takashi Iwai807a46362007-05-29 19:01:37 +02004704 /* Fix Mux capture level; max to 2 */
4705 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4706 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4707 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4708 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4709 (0 << AC_AMPCAP_MUTE_SHIFT));
4710
Matt Porter3cc08dc2006-01-23 15:27:49 +01004711 return 0;
4712}
4713
4714static int patch_stac927x(struct hda_codec *codec)
4715{
4716 struct sigmatel_spec *spec;
4717 int err;
4718
4719 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4720 if (spec == NULL)
4721 return -ENOMEM;
4722
4723 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004724 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004725 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004726 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4727 stac927x_models,
4728 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004729 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004730 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4731 if (spec->board_config < 0)
4732 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4733 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004734 err = stac92xx_save_bios_config_regs(codec);
4735 if (err < 0) {
4736 stac92xx_free(codec);
4737 return err;
4738 }
4739 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004740 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004741 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4742 stac92xx_set_config_regs(codec);
4743 }
4744
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004745 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004746 spec->adc_nids = stac927x_adc_nids;
4747 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4748 spec->mux_nids = stac927x_mux_nids;
4749 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004750 spec->smux_nids = stac927x_smux_nids;
4751 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04004752 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004753 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004754 spec->multiout.dac_nids = spec->dac_nids;
4755
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004756 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004757 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004758 case STAC_D965_5ST:
4759 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004760 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004761 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004762 spec->num_dmics = 0;
4763
Tobin Davis93ed1502006-09-01 21:03:12 +02004764 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004765 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004766 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004767 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004768 switch (codec->subsystem_id) {
4769 case 0x10280209:
4770 case 0x1028022e:
4771 /* correct the device field to SPDIF out */
4772 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4773 break;
4774 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004775 /* configure the analog microphone on some laptops */
4776 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004777 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004778 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004779 /* correct the front input jack as a mic */
4780 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4781 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004782 case STAC_DELL_3ST:
4783 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004784 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004785 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004786 spec->dmic_nids = stac927x_dmic_nids;
4787 spec->num_dmics = STAC927X_NUM_DMICS;
4788
Tobin Davis93ed1502006-09-01 21:03:12 +02004789 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004790 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004791 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01004792 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004793 break;
4794 default:
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004795 if (spec->board_config > STAC_D965_REF) {
4796 /* GPIO0 High = Enable EAPD */
4797 spec->eapd_mask = spec->gpio_mask = 0x01;
4798 spec->gpio_dir = spec->gpio_data = 0x01;
4799 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004800 spec->num_dmics = 0;
4801
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004802 spec->init = stac927x_core_init;
4803 spec->mixer = stac927x_mixer;
4804 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004805
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004806 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004807 spec->aloopback_mask = 0x40;
4808 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004809
Matt Porter3cc08dc2006-01-23 15:27:49 +01004810 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004811 if (!err) {
4812 if (spec->board_config < 0) {
4813 printk(KERN_WARNING "hda_codec: No auto-config is "
4814 "available, default to model=ref\n");
4815 spec->board_config = STAC_D965_REF;
4816 goto again;
4817 }
4818 err = -EINVAL;
4819 }
Mattc7d4b2f2005-06-27 14:59:41 +02004820 if (err < 0) {
4821 stac92xx_free(codec);
4822 return err;
4823 }
Matt2f2f4252005-04-13 14:45:30 +02004824
4825 codec->patch_ops = stac92xx_patch_ops;
4826
Takashi Iwai52987652008-01-16 16:09:47 +01004827 /*
4828 * !!FIXME!!
4829 * The STAC927x seem to require fairly long delays for certain
4830 * command sequences. With too short delays (even if the answer
4831 * is set to RIRB properly), it results in the silence output
4832 * on some hardwares like Dell.
4833 *
4834 * The below flag enables the longer delay (see get_response
4835 * in hda_intel.c).
4836 */
4837 codec->bus->needs_damn_long_delay = 1;
4838
Matt2f2f4252005-04-13 14:45:30 +02004839 return 0;
4840}
4841
Matt Porterf3302a52006-07-31 12:49:34 +02004842static int patch_stac9205(struct hda_codec *codec)
4843{
4844 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004845 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004846
4847 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4848 if (spec == NULL)
4849 return -ENOMEM;
4850
4851 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004852 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004853 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004854 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4855 stac9205_models,
4856 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004857 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004858 if (spec->board_config < 0) {
4859 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4860 err = stac92xx_save_bios_config_regs(codec);
4861 if (err < 0) {
4862 stac92xx_free(codec);
4863 return err;
4864 }
4865 spec->pin_configs = spec->bios_pin_configs;
4866 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004867 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4868 stac92xx_set_config_regs(codec);
4869 }
4870
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004871 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004872 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004873 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004874 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004875 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004876 spec->smux_nids = stac9205_smux_nids;
4877 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004878 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004879 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004880 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01004881 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004882 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004883
4884 spec->init = stac9205_core_init;
4885 spec->mixer = stac9205_mixer;
4886
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004887 spec->aloopback_mask = 0x40;
4888 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004889 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004890
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004891 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004892 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004893 /* Enable SPDIF in/out */
4894 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4895 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004896
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004897 /* Enable unsol response for GPIO4/Dock HP connection */
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01004898 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004899 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4900 snd_hda_codec_write_cache(codec, codec->afg, 0,
4901 AC_VERB_SET_UNSOLICITED_ENABLE,
4902 (AC_USRSP_EN | STAC_HP_EVENT));
4903
4904 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004905 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004906 spec->gpio_mask = 0x1b;
4907 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004908 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004909 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004910 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004911 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004912 break;
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004913 case STAC_9205_REF:
4914 /* SPDIF-In enabled */
4915 break;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004916 default:
4917 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004918 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004919 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004920 break;
4921 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004922
Matt Porterf3302a52006-07-31 12:49:34 +02004923 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004924 if (!err) {
4925 if (spec->board_config < 0) {
4926 printk(KERN_WARNING "hda_codec: No auto-config is "
4927 "available, default to model=ref\n");
4928 spec->board_config = STAC_9205_REF;
4929 goto again;
4930 }
4931 err = -EINVAL;
4932 }
Matt Porterf3302a52006-07-31 12:49:34 +02004933 if (err < 0) {
4934 stac92xx_free(codec);
4935 return err;
4936 }
4937
4938 codec->patch_ops = stac92xx_patch_ops;
4939
4940 return 0;
4941}
4942
Matt2f2f4252005-04-13 14:45:30 +02004943/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004944 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004945 */
4946
Guillaume Munch99ccc562006-08-16 19:35:12 +02004947/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004948static hda_nid_t vaio_dacs[] = { 0x2 };
4949#define VAIO_HP_DAC 0x5
4950static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4951static hda_nid_t vaio_mux_nids[] = { 0x15 };
4952
4953static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004954 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004955 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004956 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004957 { "Mic Jack", 0x1 },
4958 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004959 { "PCM", 0x3 },
4960 }
4961};
4962
4963static struct hda_verb vaio_init[] = {
4964 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004965 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004966 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4967 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4968 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4969 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004970 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004971 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4972 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4973 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4974 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4975 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4976 {}
4977};
4978
Guillaume Munch6d859062006-08-22 17:15:47 +02004979static struct hda_verb vaio_ar_init[] = {
4980 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4981 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4982 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4983 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4984/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4985 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004986 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004987 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4988 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4989/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4990 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4991 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4992 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4993 {}
4994};
4995
Takashi Iwaidb064e52006-03-16 16:04:58 +01004996/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004997static struct hda_bind_ctls vaio_bind_master_vol = {
4998 .ops = &snd_hda_bind_vol,
4999 .values = {
5000 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
5001 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
5002 0
5003 },
5004};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005005
5006/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02005007static struct hda_bind_ctls vaio_bind_master_sw = {
5008 .ops = &snd_hda_bind_sw,
5009 .values = {
5010 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
5011 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
5012 0,
5013 },
5014};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005015
5016static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02005017 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
5018 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005019 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5020 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5021 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5022 {
5023 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5024 .name = "Capture Source",
5025 .count = 1,
5026 .info = stac92xx_mux_enum_info,
5027 .get = stac92xx_mux_enum_get,
5028 .put = stac92xx_mux_enum_put,
5029 },
5030 {}
5031};
5032
Guillaume Munch6d859062006-08-22 17:15:47 +02005033static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02005034 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
5035 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02005036 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5037 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5038 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5039 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
5040 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
5041 {
5042 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5043 .name = "Capture Source",
5044 .count = 1,
5045 .info = stac92xx_mux_enum_info,
5046 .get = stac92xx_mux_enum_get,
5047 .put = stac92xx_mux_enum_put,
5048 },
5049 {}
5050};
5051
5052static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01005053 .build_controls = stac92xx_build_controls,
5054 .build_pcms = stac92xx_build_pcms,
5055 .init = stac92xx_init,
5056 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005057#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01005058 .resume = stac92xx_resume,
5059#endif
5060};
5061
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005062static int stac9872_vaio_init(struct hda_codec *codec)
5063{
5064 int err;
5065
5066 err = stac92xx_init(codec);
5067 if (err < 0)
5068 return err;
5069 if (codec->patch_ops.unsol_event)
5070 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
5071 return 0;
5072}
5073
5074static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
5075{
Jiang Zhe40c1d302007-11-12 13:05:16 +01005076 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005077 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5078 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5079 } else {
5080 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5081 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5082 }
5083}
5084
5085static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
5086{
5087 switch (res >> 26) {
5088 case STAC_HP_EVENT:
5089 stac9872_vaio_hp_detect(codec, res);
5090 break;
5091 }
5092}
5093
5094static struct hda_codec_ops stac9872_vaio_patch_ops = {
5095 .build_controls = stac92xx_build_controls,
5096 .build_pcms = stac92xx_build_pcms,
5097 .init = stac9872_vaio_init,
5098 .free = stac92xx_free,
5099 .unsol_event = stac9872_vaio_unsol_event,
5100#ifdef CONFIG_PM
5101 .resume = stac92xx_resume,
5102#endif
5103};
5104
Guillaume Munch6d859062006-08-22 17:15:47 +02005105enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
5106 CXD9872RD_VAIO,
5107 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
5108 STAC9872AK_VAIO,
5109 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
5110 STAC9872K_VAIO,
5111 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005112 CXD9872AKD_VAIO,
5113 STAC_9872_MODELS,
5114};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005115
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005116static const char *stac9872_models[STAC_9872_MODELS] = {
5117 [CXD9872RD_VAIO] = "vaio",
5118 [CXD9872AKD_VAIO] = "vaio-ar",
5119};
5120
5121static struct snd_pci_quirk stac9872_cfg_tbl[] = {
5122 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
5123 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
5124 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01005125 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005126 {}
5127};
5128
Guillaume Munch6d859062006-08-22 17:15:47 +02005129static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01005130{
5131 struct sigmatel_spec *spec;
5132 int board_config;
5133
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005134 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
5135 stac9872_models,
5136 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01005137 if (board_config < 0)
5138 /* unknown config, let generic-parser do its job... */
5139 return snd_hda_parse_generic_codec(codec);
5140
5141 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5142 if (spec == NULL)
5143 return -ENOMEM;
5144
5145 codec->spec = spec;
5146 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02005147 case CXD9872RD_VAIO:
5148 case STAC9872AK_VAIO:
5149 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01005150 spec->mixer = vaio_mixer;
5151 spec->init = vaio_init;
5152 spec->multiout.max_channels = 2;
5153 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5154 spec->multiout.dac_nids = vaio_dacs;
5155 spec->multiout.hp_nid = VAIO_HP_DAC;
5156 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
5157 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005158 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005159 spec->input_mux = &vaio_mux;
5160 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005161 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005162 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02005163
5164 case CXD9872AKD_VAIO:
5165 spec->mixer = vaio_ar_mixer;
5166 spec->init = vaio_ar_init;
5167 spec->multiout.max_channels = 2;
5168 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5169 spec->multiout.dac_nids = vaio_dacs;
5170 spec->multiout.hp_nid = VAIO_HP_DAC;
5171 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005172 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02005173 spec->adc_nids = vaio_adcs;
5174 spec->input_mux = &vaio_mux;
5175 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005176 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02005177 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005178 }
5179
Takashi Iwaidb064e52006-03-16 16:04:58 +01005180 return 0;
5181}
5182
5183
5184/*
Matt2f2f4252005-04-13 14:45:30 +02005185 * patch entries
5186 */
5187struct hda_codec_preset snd_hda_preset_sigmatel[] = {
5188 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
5189 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
5190 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
5191 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
5192 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
5193 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
5194 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02005195 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
5196 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
5197 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
5198 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
5199 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
5200 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01005201 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
5202 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
5203 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
5204 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
5205 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
5206 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
5207 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
5208 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
5209 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
5210 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01005211 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
5212 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
5213 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
5214 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
5215 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
5216 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02005217 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
5218 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02005219 /* The following does not take into account .id=0x83847661 when subsys =
5220 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
5221 * currently not fully supported.
5222 */
5223 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
5224 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
5225 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02005226 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
5227 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
5228 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
5229 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
5230 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
5231 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
5232 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
5233 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005234 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005235 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
5236 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005237 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01005238 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
5239 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005240 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01005241 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5242 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5243 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5244 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5245 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5246 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5247 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
5248 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02005249 {} /* terminator */
5250};