blob: 7c8cd59852ece2a7939234ebcc13dbcdda75699d [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"
35
Matt4e550962005-07-04 17:51:39 +020036#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010037#define STAC_PWR_EVENT 0x20
38#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020039
Takashi Iwaif5fcc132006-11-24 17:07:44 +010040enum {
41 STAC_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020042 STAC_9200_DELL_D21,
43 STAC_9200_DELL_D22,
44 STAC_9200_DELL_D23,
45 STAC_9200_DELL_M21,
46 STAC_9200_DELL_M22,
47 STAC_9200_DELL_M23,
48 STAC_9200_DELL_M24,
49 STAC_9200_DELL_M25,
50 STAC_9200_DELL_M26,
51 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020052 STAC_9200_GATEWAY,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010053 STAC_9200_MODELS
54};
55
56enum {
57 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020058 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020059 STAC_9205_DELL_M43,
60 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010061 STAC_9205_MODELS
62};
63
64enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010065 STAC_92HD73XX_REF,
66 STAC_92HD73XX_MODELS
67};
68
69enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010070 STAC_92HD71BXX_REF,
71 STAC_92HD71BXX_MODELS
72};
73
74enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010075 STAC_925x_REF,
76 STAC_M2_2,
77 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020078 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010079 STAC_925x_MODELS
80};
81
82enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010083 STAC_D945_REF,
84 STAC_D945GTP3,
85 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020086 STAC_INTEL_MAC_V1,
87 STAC_INTEL_MAC_V2,
88 STAC_INTEL_MAC_V3,
89 STAC_INTEL_MAC_V4,
90 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020091 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010092 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010093 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010094 STAC_MACBOOK_PRO_V1,
95 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +020096 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +020097 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020098 STAC_922X_DELL_D81,
99 STAC_922X_DELL_D82,
100 STAC_922X_DELL_M81,
101 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100102 STAC_922X_MODELS
103};
104
105enum {
106 STAC_D965_REF,
107 STAC_D965_3ST,
108 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200109 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100110 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100111 STAC_927X_MODELS
112};
Matt Porter403d1942005-11-29 15:00:51 +0100113
Matt2f2f4252005-04-13 14:45:30 +0200114struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100115 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200116 unsigned int num_mixers;
117
Matt Porter403d1942005-11-29 15:00:51 +0100118 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200119 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100120 unsigned int line_switch: 1;
121 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100122 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100123 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200124
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100125 /* gpio lines */
126 unsigned int gpio_mask;
127 unsigned int gpio_dir;
128 unsigned int gpio_data;
129 unsigned int gpio_mute;
130
131 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100132 unsigned char aloopback_mask;
133 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200134
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100135 /* power management */
136 unsigned int num_pwrs;
137 hda_nid_t *pwr_nids;
138
Matt2f2f4252005-04-13 14:45:30 +0200139 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100140 struct hda_input_mux *mono_mux;
141 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200142 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100143 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200144
145 /* capture */
146 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200147 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200148 hda_nid_t *mux_nids;
149 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200150 hda_nid_t *dmic_nids;
151 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100152 hda_nid_t *dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +0100153 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200154 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100155 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200156
Matt2f2f4252005-04-13 14:45:30 +0200157 /* pin widgets */
158 hda_nid_t *pin_nids;
159 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200160 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200161 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200162
163 /* codec specific stuff */
164 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100165 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200166
167 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200168 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100169 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200170 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100171 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200172
Matt Porter403d1942005-11-29 15:00:51 +0100173 /* i/o switches */
174 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200175 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200176 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200177
Mattc7d4b2f2005-06-27 14:59:41 +0200178 struct hda_pcm pcm_rec[2]; /* PCM information */
179
180 /* dynamic controls and input_mux */
181 struct auto_pin_cfg autocfg;
182 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100183 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200184 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200185 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100186 struct hda_input_mux private_mono_mux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100187
188 /* virtual master */
189 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200190};
191
192static hda_nid_t stac9200_adc_nids[1] = {
193 0x03,
194};
195
196static hda_nid_t stac9200_mux_nids[1] = {
197 0x0c,
198};
199
200static hda_nid_t stac9200_dac_nids[1] = {
201 0x02,
202};
203
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100204static hda_nid_t stac92hd73xx_pwr_nids[8] = {
205 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
206 0x0f, 0x10, 0x11
207};
208
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100209static hda_nid_t stac92hd73xx_adc_nids[2] = {
210 0x1a, 0x1b
211};
212
213#define STAC92HD73XX_NUM_DMICS 2
214static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
215 0x13, 0x14, 0
216};
217
218#define STAC92HD73_DAC_COUNT 5
219static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
220 0x15, 0x16, 0x17, 0x18, 0x19,
221};
222
223static hda_nid_t stac92hd73xx_mux_nids[4] = {
224 0x28, 0x29, 0x2a, 0x2b,
225};
226
227static hda_nid_t stac92hd73xx_dmux_nids[2] = {
228 0x20, 0x21,
229};
230
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100231static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
232 0x0a, 0x0d, 0x0f
233};
234
Matthew Ranostaye035b842007-11-06 11:53:55 +0100235static hda_nid_t stac92hd71bxx_adc_nids[2] = {
236 0x12, 0x13,
237};
238
239static hda_nid_t stac92hd71bxx_mux_nids[2] = {
240 0x1a, 0x1b
241};
242
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100243static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
244 0x1c,
245};
246
Matthew Ranostaye035b842007-11-06 11:53:55 +0100247static hda_nid_t stac92hd71bxx_dac_nids[2] = {
248 0x10, /*0x11, */
249};
250
251#define STAC92HD71BXX_NUM_DMICS 2
252static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
253 0x18, 0x19, 0
254};
255
Tobin Davis8e21c342007-01-08 11:04:17 +0100256static hda_nid_t stac925x_adc_nids[1] = {
257 0x03,
258};
259
260static hda_nid_t stac925x_mux_nids[1] = {
261 0x0f,
262};
263
264static hda_nid_t stac925x_dac_nids[1] = {
265 0x02,
266};
267
Takashi Iwaif6e98522007-10-16 14:27:04 +0200268#define STAC925X_NUM_DMICS 1
269static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
270 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200271};
272
Takashi Iwai16970552007-12-18 18:05:52 +0100273static hda_nid_t stac925x_dmux_nids[1] = {
274 0x14,
275};
276
Matt2f2f4252005-04-13 14:45:30 +0200277static hda_nid_t stac922x_adc_nids[2] = {
278 0x06, 0x07,
279};
280
281static hda_nid_t stac922x_mux_nids[2] = {
282 0x12, 0x13,
283};
284
Matt Porter3cc08dc2006-01-23 15:27:49 +0100285static hda_nid_t stac927x_adc_nids[3] = {
286 0x07, 0x08, 0x09
287};
288
289static hda_nid_t stac927x_mux_nids[3] = {
290 0x15, 0x16, 0x17
291};
292
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100293static hda_nid_t stac927x_dmux_nids[1] = {
294 0x1b,
295};
296
Matthew Ranostay7f168592007-10-18 17:38:17 +0200297#define STAC927X_NUM_DMICS 2
298static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
299 0x13, 0x14, 0
300};
301
Matt Porterf3302a52006-07-31 12:49:34 +0200302static hda_nid_t stac9205_adc_nids[2] = {
303 0x12, 0x13
304};
305
306static hda_nid_t stac9205_mux_nids[2] = {
307 0x19, 0x1a
308};
309
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100310static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai16970552007-12-18 18:05:52 +0100311 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100312};
313
Takashi Iwaif6e98522007-10-16 14:27:04 +0200314#define STAC9205_NUM_DMICS 2
315static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
316 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200317};
318
Mattc7d4b2f2005-06-27 14:59:41 +0200319static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200320 0x08, 0x09, 0x0d, 0x0e,
321 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200322};
323
Tobin Davis8e21c342007-01-08 11:04:17 +0100324static hda_nid_t stac925x_pin_nids[8] = {
325 0x07, 0x08, 0x0a, 0x0b,
326 0x0c, 0x0d, 0x10, 0x11,
327};
328
Matt2f2f4252005-04-13 14:45:30 +0200329static hda_nid_t stac922x_pin_nids[10] = {
330 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
331 0x0f, 0x10, 0x11, 0x15, 0x1b,
332};
333
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100334static hda_nid_t stac92hd73xx_pin_nids[12] = {
335 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
336 0x0f, 0x10, 0x11, 0x12, 0x13,
337 0x14, 0x22
338};
339
Matthew Ranostaye035b842007-11-06 11:53:55 +0100340static hda_nid_t stac92hd71bxx_pin_nids[10] = {
341 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
342 0x0f, 0x14, 0x18, 0x19, 0x1e,
343};
344
Matt Porter3cc08dc2006-01-23 15:27:49 +0100345static hda_nid_t stac927x_pin_nids[14] = {
346 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
347 0x0f, 0x10, 0x11, 0x12, 0x13,
348 0x14, 0x21, 0x22, 0x23,
349};
350
Matt Porterf3302a52006-07-31 12:49:34 +0200351static hda_nid_t stac9205_pin_nids[12] = {
352 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
353 0x0f, 0x14, 0x16, 0x17, 0x18,
354 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200355};
356
Matt Porter8b657272006-10-26 17:12:59 +0200357static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
358 struct snd_ctl_elem_info *uinfo)
359{
360 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
361 struct sigmatel_spec *spec = codec->spec;
362 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
363}
364
365static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_value *ucontrol)
367{
368 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
369 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100370 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200371
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100372 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200373 return 0;
374}
375
376static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
378{
379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
380 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100381 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200382
383 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100384 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200385}
386
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100387static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200388{
389 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
390 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200391 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200392}
393
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100394static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200395{
396 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
397 struct sigmatel_spec *spec = codec->spec;
398 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
399
400 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
401 return 0;
402}
403
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100404static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200405{
406 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
407 struct sigmatel_spec *spec = codec->spec;
408 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
409
Mattc7d4b2f2005-06-27 14:59:41 +0200410 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200411 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
412}
413
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100414static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
415 struct snd_ctl_elem_info *uinfo)
416{
417 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
418 struct sigmatel_spec *spec = codec->spec;
419 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
420}
421
422static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
423 struct snd_ctl_elem_value *ucontrol)
424{
425 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
426 struct sigmatel_spec *spec = codec->spec;
427
428 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
429 return 0;
430}
431
432static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
433 struct snd_ctl_elem_value *ucontrol)
434{
435 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
436 struct sigmatel_spec *spec = codec->spec;
437
438 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
439 spec->mono_nid, &spec->cur_mmux);
440}
441
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200442#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
443
444static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
445 struct snd_ctl_elem_value *ucontrol)
446{
447 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100448 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200449 struct sigmatel_spec *spec = codec->spec;
450
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100451 ucontrol->value.integer.value[0] = !!(spec->aloopback &
452 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200453 return 0;
454}
455
456static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
457 struct snd_ctl_elem_value *ucontrol)
458{
459 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
460 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100461 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200462 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100463 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200464
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100465 idx_val = spec->aloopback_mask << idx;
466 if (ucontrol->value.integer.value[0])
467 val = spec->aloopback | idx_val;
468 else
469 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100470 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200471 return 0;
472
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100473 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200474
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100475 /* Only return the bits defined by the shift value of the
476 * first two bytes of the mask
477 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200478 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100479 kcontrol->private_value & 0xFFFF, 0x0);
480 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200481
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100482 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200483 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100484 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200485 } else {
486 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100487 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200488 }
489
490 snd_hda_codec_write_cache(codec, codec->afg, 0,
491 kcontrol->private_value >> 16, dac_mode);
492
493 return 1;
494}
495
Mattc7d4b2f2005-06-27 14:59:41 +0200496static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200497 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200498 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200499 {}
500};
501
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200502static struct hda_verb stac9200_eapd_init[] = {
503 /* set dac0mux for dac converter */
504 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
505 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
506 {}
507};
508
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100509static struct hda_verb stac92hd73xx_6ch_core_init[] = {
510 /* set master volume and direct control */
511 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
512 /* setup audio connections */
513 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
514 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
515 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
516 /* setup adcs to point to mixer */
517 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
518 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100519 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
520 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
521 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
522 /* setup import muxs */
523 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
524 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
525 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
526 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
527 {}
528};
529
530static struct hda_verb stac92hd73xx_8ch_core_init[] = {
531 /* set master volume and direct control */
532 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
533 /* setup audio connections */
534 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
535 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
536 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
537 /* connect hp ports to dac3 */
538 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
539 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
540 /* setup adcs to point to mixer */
541 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
542 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100543 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
544 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
545 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
546 /* setup import muxs */
547 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
548 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
549 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
550 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
551 {}
552};
553
554static struct hda_verb stac92hd73xx_10ch_core_init[] = {
555 /* set master volume and direct control */
556 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
557 /* setup audio connections */
558 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
559 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
560 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
561 /* dac3 is connected to import3 mux */
562 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
563 /* connect hp ports to dac4 */
564 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
565 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
566 /* setup adcs to point to mixer */
567 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
568 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100569 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
570 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
571 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
572 /* setup import muxs */
573 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
574 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
575 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
576 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
577 {}
578};
579
Matthew Ranostaye035b842007-11-06 11:53:55 +0100580static struct hda_verb stac92hd71bxx_core_init[] = {
581 /* set master volume and direct control */
582 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
583 /* connect headphone jack to dac1 */
584 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100585 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
586 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
587 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
588 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
589 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100590};
591
592static struct hda_verb stac92hd71bxx_analog_core_init[] = {
593 /* set master volume and direct control */
594 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
595 /* connect headphone jack to dac1 */
596 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100597 /* connect ports 0d and 0f to audio mixer */
598 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
599 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100600 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100601 /* unmute dac0 input in audio mixer */
602 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100603 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
604 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
605 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
606 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100607 {}
608};
609
Tobin Davis8e21c342007-01-08 11:04:17 +0100610static struct hda_verb stac925x_core_init[] = {
611 /* set dac0mux for dac converter */
612 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
613 {}
614};
615
Mattc7d4b2f2005-06-27 14:59:41 +0200616static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200617 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200618 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200619 {}
620};
621
Tobin Davis93ed1502006-09-01 21:03:12 +0200622static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200623 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200624 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200625 /* unmute node 0x1b */
626 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
627 /* select node 0x03 as DAC */
628 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
629 {}
630};
631
Matt Porter3cc08dc2006-01-23 15:27:49 +0100632static struct hda_verb stac927x_core_init[] = {
633 /* set master volume and direct control */
634 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
635 {}
636};
637
Matt Porterf3302a52006-07-31 12:49:34 +0200638static struct hda_verb stac9205_core_init[] = {
639 /* set master volume and direct control */
640 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
641 {}
642};
643
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100644#define STAC_MONO_MUX \
645 { \
646 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
647 .name = "Mono Mux", \
648 .count = 1, \
649 .info = stac92xx_mono_mux_enum_info, \
650 .get = stac92xx_mono_mux_enum_get, \
651 .put = stac92xx_mono_mux_enum_put, \
652 }
653
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200654#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200655 { \
656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
657 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200658 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200659 .info = stac92xx_mux_enum_info, \
660 .get = stac92xx_mux_enum_get, \
661 .put = stac92xx_mux_enum_put, \
662 }
663
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100664#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200665 { \
666 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
667 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100668 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200669 .info = stac92xx_aloopback_info, \
670 .get = stac92xx_aloopback_get, \
671 .put = stac92xx_aloopback_put, \
672 .private_value = verb_read | (verb_write << 16), \
673 }
674
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100675static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200676 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
677 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200678 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200679 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
680 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200681 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200682 { } /* end */
683};
684
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100685static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100686 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
687
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100688 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
689 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
690
691 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
692 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
693
694 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
695 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
696
697 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
698 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
699
700 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
701 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
702
703 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
704 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
705
706 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
707 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
708 { } /* end */
709};
710
711static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100712 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
713
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100714 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
715 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
716
717 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
718 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
719
720 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
721 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
722
723 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
724 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
725
726 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
727 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
728
729 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
730 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
731
732 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
733 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
734 { } /* end */
735};
736
737static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100738 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
739
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100740 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
741 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
742
743 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
744 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
745
746 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
747 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
748
749 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
750 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
751
752 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
753 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
754
755 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
756 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
757
758 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
759 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
760 { } /* end */
761};
762
Matthew Ranostay541eee82007-12-14 12:08:04 +0100763static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100764 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100765
Matthew Ranostay9b359472007-11-07 13:03:12 +0100766 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
767 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
768 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
769
770 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
771 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
772 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
773
774 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
775 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100776 { } /* end */
777};
778
Matthew Ranostay541eee82007-12-14 12:08:04 +0100779static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100780 STAC_INPUT_SOURCE(2),
781 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
782
Matthew Ranostay541eee82007-12-14 12:08:04 +0100783 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
784 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
785 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
786
787 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
788 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
789 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
790 { } /* end */
791};
792
Tobin Davis8e21c342007-01-08 11:04:17 +0100793static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200794 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100795 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
796 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
797 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
798 { } /* end */
799};
800
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100801static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200802 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100803 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200804
805 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
806 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
807 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
808
809 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
810 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
811 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
812
813 { } /* end */
814};
815
816/* This needs to be generated dynamically based on sequence */
817static struct snd_kcontrol_new stac922x_mixer[] = {
818 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200819 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
820 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
821 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
822
823 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
824 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
825 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
826 { } /* end */
827};
828
829
830static struct snd_kcontrol_new stac927x_mixer[] = {
831 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100832 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200833
834 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
835 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
836 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
837
838 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
839 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
840 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
841
842 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
843 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
844 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200845 { } /* end */
846};
847
Takashi Iwai16970552007-12-18 18:05:52 +0100848static struct snd_kcontrol_new stac_dmux_mixer = {
849 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
850 .name = "Digital Input Source",
851 /* count set later */
852 .info = stac92xx_dmux_enum_info,
853 .get = stac92xx_dmux_enum_get,
854 .put = stac92xx_dmux_enum_put,
855};
856
Takashi Iwai2134ea42008-01-10 16:53:55 +0100857static const char *slave_vols[] = {
858 "Front Playback Volume",
859 "Surround Playback Volume",
860 "Center Playback Volume",
861 "LFE Playback Volume",
862 "Side Playback Volume",
863 "Headphone Playback Volume",
864 "Headphone Playback Volume",
865 "Speaker Playback Volume",
866 "External Speaker Playback Volume",
867 "Speaker2 Playback Volume",
868 NULL
869};
870
871static const char *slave_sws[] = {
872 "Front Playback Switch",
873 "Surround Playback Switch",
874 "Center Playback Switch",
875 "LFE Playback Switch",
876 "Side Playback Switch",
877 "Headphone Playback Switch",
878 "Headphone Playback Switch",
879 "Speaker Playback Switch",
880 "External Speaker Playback Switch",
881 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100882 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100883 NULL
884};
885
Matt2f2f4252005-04-13 14:45:30 +0200886static int stac92xx_build_controls(struct hda_codec *codec)
887{
888 struct sigmatel_spec *spec = codec->spec;
889 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200890 int i;
Matt2f2f4252005-04-13 14:45:30 +0200891
892 err = snd_hda_add_new_ctls(codec, spec->mixer);
893 if (err < 0)
894 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200895
896 for (i = 0; i < spec->num_mixers; i++) {
897 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
898 if (err < 0)
899 return err;
900 }
Takashi Iwai16970552007-12-18 18:05:52 +0100901 if (spec->num_dmuxes > 0) {
902 stac_dmux_mixer.count = spec->num_dmuxes;
903 err = snd_ctl_add(codec->bus->card,
904 snd_ctl_new1(&stac_dmux_mixer, codec));
905 if (err < 0)
906 return err;
907 }
Mattc7d4b2f2005-06-27 14:59:41 +0200908
Mattdabbed62005-06-14 10:19:34 +0200909 if (spec->multiout.dig_out_nid) {
910 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
911 if (err < 0)
912 return err;
913 }
914 if (spec->dig_in_nid) {
915 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
916 if (err < 0)
917 return err;
918 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100919
920 /* if we have no master control, let's create it */
921 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
922 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
923 HDA_OUTPUT, spec->vmaster_tlv);
924 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
925 spec->vmaster_tlv, slave_vols);
926 if (err < 0)
927 return err;
928 }
929 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
930 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
931 NULL, slave_sws);
932 if (err < 0)
933 return err;
934 }
935
Mattdabbed62005-06-14 10:19:34 +0200936 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200937}
938
Matt Porter403d1942005-11-29 15:00:51 +0100939static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200940 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200941 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
942};
943
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200944/*
945 STAC 9200 pin configs for
946 102801A8
947 102801DE
948 102801E8
949*/
950static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200951 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
952 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200953};
954
955/*
956 STAC 9200 pin configs for
957 102801C0
958 102801C1
959*/
960static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200961 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
962 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200963};
964
965/*
966 STAC 9200 pin configs for
967 102801C4 (Dell Dimension E310)
968 102801C5
969 102801C7
970 102801D9
971 102801DA
972 102801E3
973*/
974static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200975 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
976 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200977};
978
979
980/*
981 STAC 9200-32 pin configs for
982 102801B5 (Dell Inspiron 630m)
983 102801D8 (Dell Inspiron 640m)
984*/
985static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200986 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
987 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200988};
989
990/*
991 STAC 9200-32 pin configs for
992 102801C2 (Dell Latitude D620)
993 102801C8
994 102801CC (Dell Latitude D820)
995 102801D4
996 102801D6
997*/
998static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200999 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1000 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001001};
1002
1003/*
1004 STAC 9200-32 pin configs for
1005 102801CE (Dell XPS M1710)
1006 102801CF (Dell Precision M90)
1007*/
1008static unsigned int dell9200_m23_pin_configs[8] = {
1009 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1010 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1011};
1012
1013/*
1014 STAC 9200-32 pin configs for
1015 102801C9
1016 102801CA
1017 102801CB (Dell Latitude 120L)
1018 102801D3
1019*/
1020static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001021 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1022 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001023};
1024
1025/*
1026 STAC 9200-32 pin configs for
1027 102801BD (Dell Inspiron E1505n)
1028 102801EE
1029 102801EF
1030*/
1031static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001032 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1033 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001034};
1035
1036/*
1037 STAC 9200-32 pin configs for
1038 102801F5 (Dell Inspiron 1501)
1039 102801F6
1040*/
1041static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001042 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1043 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001044};
1045
1046/*
1047 STAC 9200-32
1048 102801CD (Dell Inspiron E1705/9400)
1049*/
1050static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001051 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1052 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001053};
1054
1055
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001056static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1057 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001058 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1059 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1060 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1061 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1062 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1063 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1064 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1065 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1066 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1067 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001068};
1069
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001070static const char *stac9200_models[STAC_9200_MODELS] = {
1071 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001072 [STAC_9200_DELL_D21] = "dell-d21",
1073 [STAC_9200_DELL_D22] = "dell-d22",
1074 [STAC_9200_DELL_D23] = "dell-d23",
1075 [STAC_9200_DELL_M21] = "dell-m21",
1076 [STAC_9200_DELL_M22] = "dell-m22",
1077 [STAC_9200_DELL_M23] = "dell-m23",
1078 [STAC_9200_DELL_M24] = "dell-m24",
1079 [STAC_9200_DELL_M25] = "dell-m25",
1080 [STAC_9200_DELL_M26] = "dell-m26",
1081 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001082 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001083};
1084
1085static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1086 /* SigmaTel reference board */
1087 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1088 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001089 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001090 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1091 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001092 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001093 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1094 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1095 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1096 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1097 "unknown Dell", STAC_9200_DELL_D22),
1098 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1099 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001100 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001101 "Dell Latitude D620", STAC_9200_DELL_M22),
1102 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1103 "unknown Dell", STAC_9200_DELL_D23),
1104 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1105 "unknown Dell", STAC_9200_DELL_D23),
1106 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1107 "unknown Dell", STAC_9200_DELL_M22),
1108 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1109 "unknown Dell", STAC_9200_DELL_M24),
1110 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1111 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001112 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001113 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001114 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001115 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001116 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001117 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001118 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001119 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001120 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001121 "Dell Precision M90", STAC_9200_DELL_M23),
1122 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1123 "unknown Dell", STAC_9200_DELL_M22),
1124 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1125 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001126 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001127 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001128 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001129 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1130 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1131 "unknown Dell", STAC_9200_DELL_D23),
1132 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1133 "unknown Dell", STAC_9200_DELL_D23),
1134 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1135 "unknown Dell", STAC_9200_DELL_D21),
1136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1137 "unknown Dell", STAC_9200_DELL_D23),
1138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1139 "unknown Dell", STAC_9200_DELL_D21),
1140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1141 "unknown Dell", STAC_9200_DELL_M25),
1142 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1143 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001144 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001145 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1146 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1147 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001148 /* Panasonic */
1149 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001150 /* Gateway machines needs EAPD to be set on resume */
1151 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1152 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1153 STAC_9200_GATEWAY),
1154 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1155 STAC_9200_GATEWAY),
Matt Porter403d1942005-11-29 15:00:51 +01001156 {} /* terminator */
1157};
1158
Tobin Davis8e21c342007-01-08 11:04:17 +01001159static unsigned int ref925x_pin_configs[8] = {
1160 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001161 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001162};
1163
1164static unsigned int stac925x_MA6_pin_configs[8] = {
1165 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1166 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1167};
1168
Tobin Davis2c11f952007-05-17 09:36:34 +02001169static unsigned int stac925x_PA6_pin_configs[8] = {
1170 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1171 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1172};
1173
Tobin Davis8e21c342007-01-08 11:04:17 +01001174static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001175 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1176 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001177};
1178
1179static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1180 [STAC_REF] = ref925x_pin_configs,
1181 [STAC_M2_2] = stac925xM2_2_pin_configs,
1182 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001183 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001184};
1185
1186static const char *stac925x_models[STAC_925x_MODELS] = {
1187 [STAC_REF] = "ref",
1188 [STAC_M2_2] = "m2-2",
1189 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001190 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001191};
1192
1193static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1194 /* SigmaTel reference board */
1195 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001196 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001197 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1198 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1199 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001200 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001201 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1202 {} /* terminator */
1203};
1204
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001205static unsigned int ref92hd73xx_pin_configs[12] = {
1206 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1207 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1208 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1209};
1210
1211static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1212 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1213};
1214
1215static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1216 [STAC_92HD73XX_REF] = "ref",
1217};
1218
1219static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1220 /* SigmaTel reference board */
1221 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1222 "DFI LanParty", STAC_92HD73XX_REF),
1223 {} /* terminator */
1224};
1225
Matthew Ranostaye035b842007-11-06 11:53:55 +01001226static unsigned int ref92hd71bxx_pin_configs[10] = {
1227 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001228 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001229 0x90a000f0, 0x01452050,
1230};
1231
1232static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1233 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1234};
1235
1236static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1237 [STAC_92HD71BXX_REF] = "ref",
1238};
1239
1240static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1241 /* SigmaTel reference board */
1242 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1243 "DFI LanParty", STAC_92HD71BXX_REF),
1244 {} /* terminator */
1245};
1246
Matt Porter403d1942005-11-29 15:00:51 +01001247static unsigned int ref922x_pin_configs[10] = {
1248 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1249 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001250 0x40000100, 0x40000100,
1251};
1252
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001253/*
1254 STAC 922X pin configs for
1255 102801A7
1256 102801AB
1257 102801A9
1258 102801D1
1259 102801D2
1260*/
1261static unsigned int dell_922x_d81_pin_configs[10] = {
1262 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1263 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1264 0x01813122, 0x400001f2,
1265};
1266
1267/*
1268 STAC 922X pin configs for
1269 102801AC
1270 102801D0
1271*/
1272static unsigned int dell_922x_d82_pin_configs[10] = {
1273 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1274 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1275 0x01813122, 0x400001f1,
1276};
1277
1278/*
1279 STAC 922X pin configs for
1280 102801BF
1281*/
1282static unsigned int dell_922x_m81_pin_configs[10] = {
1283 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1284 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1285 0x40C003f1, 0x405003f0,
1286};
1287
1288/*
1289 STAC 9221 A1 pin configs for
1290 102801D7 (Dell XPS M1210)
1291*/
1292static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001293 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1294 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001295 0x508003f3, 0x405003f4,
1296};
1297
Matt Porter403d1942005-11-29 15:00:51 +01001298static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001299 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001300 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1301 0x02a19120, 0x40000100,
1302};
1303
1304static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001305 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1306 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001307 0x02a19320, 0x40000100,
1308};
1309
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001310static unsigned int intel_mac_v1_pin_configs[10] = {
1311 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1312 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001313 0x400000fc, 0x400000fb,
1314};
1315
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001316static unsigned int intel_mac_v2_pin_configs[10] = {
1317 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1318 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001319 0x400000fc, 0x400000fb,
1320};
1321
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001322static unsigned int intel_mac_v3_pin_configs[10] = {
1323 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1324 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1325 0x400000fc, 0x400000fb,
1326};
1327
1328static unsigned int intel_mac_v4_pin_configs[10] = {
1329 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1330 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1331 0x400000fc, 0x400000fb,
1332};
1333
1334static unsigned int intel_mac_v5_pin_configs[10] = {
1335 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1336 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1337 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001338};
1339
Takashi Iwai76c08822007-06-19 12:17:42 +02001340
Takashi Iwai19039bd2006-06-28 15:52:16 +02001341static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001342 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001343 [STAC_D945GTP3] = d945gtp3_pin_configs,
1344 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001345 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1346 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1347 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1348 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1349 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001350 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001351 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1352 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1353 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1354 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1355 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1356 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001357 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1358 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1359 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1360 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001361};
1362
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001363static const char *stac922x_models[STAC_922X_MODELS] = {
1364 [STAC_D945_REF] = "ref",
1365 [STAC_D945GTP5] = "5stack",
1366 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001367 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1368 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1369 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1370 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1371 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001372 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001373 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001374 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001375 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1376 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001377 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001378 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001379 [STAC_922X_DELL_D81] = "dell-d81",
1380 [STAC_922X_DELL_D82] = "dell-d82",
1381 [STAC_922X_DELL_M81] = "dell-m81",
1382 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001383};
1384
1385static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1386 /* SigmaTel reference board */
1387 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1388 "DFI LanParty", STAC_D945_REF),
1389 /* Intel 945G based systems */
1390 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1391 "Intel D945G", STAC_D945GTP3),
1392 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1393 "Intel D945G", STAC_D945GTP3),
1394 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1395 "Intel D945G", STAC_D945GTP3),
1396 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1397 "Intel D945G", STAC_D945GTP3),
1398 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1399 "Intel D945G", STAC_D945GTP3),
1400 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1401 "Intel D945G", STAC_D945GTP3),
1402 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1403 "Intel D945G", STAC_D945GTP3),
1404 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1405 "Intel D945G", STAC_D945GTP3),
1406 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1407 "Intel D945G", STAC_D945GTP3),
1408 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1409 "Intel D945G", STAC_D945GTP3),
1410 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1411 "Intel D945G", STAC_D945GTP3),
1412 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1413 "Intel D945G", STAC_D945GTP3),
1414 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1415 "Intel D945G", STAC_D945GTP3),
1416 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1417 "Intel D945G", STAC_D945GTP3),
1418 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1419 "Intel D945G", STAC_D945GTP3),
1420 /* Intel D945G 5-stack systems */
1421 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1422 "Intel D945G", STAC_D945GTP5),
1423 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1424 "Intel D945G", STAC_D945GTP5),
1425 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1426 "Intel D945G", STAC_D945GTP5),
1427 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1428 "Intel D945G", STAC_D945GTP5),
1429 /* Intel 945P based systems */
1430 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1431 "Intel D945P", STAC_D945GTP3),
1432 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1433 "Intel D945P", STAC_D945GTP3),
1434 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1435 "Intel D945P", STAC_D945GTP3),
1436 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1437 "Intel D945P", STAC_D945GTP3),
1438 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1439 "Intel D945P", STAC_D945GTP3),
1440 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1441 "Intel D945P", STAC_D945GTP5),
1442 /* other systems */
1443 /* Apple Mac Mini (early 2006) */
1444 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001445 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001446 /* Dell systems */
1447 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1448 "unknown Dell", STAC_922X_DELL_D81),
1449 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1450 "unknown Dell", STAC_922X_DELL_D81),
1451 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1452 "unknown Dell", STAC_922X_DELL_D81),
1453 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1454 "unknown Dell", STAC_922X_DELL_D82),
1455 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1456 "unknown Dell", STAC_922X_DELL_M81),
1457 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1458 "unknown Dell", STAC_922X_DELL_D82),
1459 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1460 "unknown Dell", STAC_922X_DELL_D81),
1461 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1462 "unknown Dell", STAC_922X_DELL_D81),
1463 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1464 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001465 {} /* terminator */
1466};
1467
Matt Porter3cc08dc2006-01-23 15:27:49 +01001468static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001469 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1470 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1471 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1472 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001473};
1474
Tobin Davis93ed1502006-09-01 21:03:12 +02001475static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001476 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1477 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1478 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1479 0x40000100, 0x40000100
1480};
1481
Tobin Davis93ed1502006-09-01 21:03:12 +02001482static unsigned int d965_5st_pin_configs[14] = {
1483 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1484 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1485 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1486 0x40000100, 0x40000100
1487};
1488
Tobin Davis4ff076e2007-08-07 11:48:12 +02001489static unsigned int dell_3st_pin_configs[14] = {
1490 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1491 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001492 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001493 0x40c003fc, 0x40000100
1494};
1495
Tobin Davis93ed1502006-09-01 21:03:12 +02001496static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001497 [STAC_D965_REF] = ref927x_pin_configs,
1498 [STAC_D965_3ST] = d965_3st_pin_configs,
1499 [STAC_D965_5ST] = d965_5st_pin_configs,
1500 [STAC_DELL_3ST] = dell_3st_pin_configs,
1501 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001502};
1503
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001504static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001505 [STAC_D965_REF] = "ref",
1506 [STAC_D965_3ST] = "3stack",
1507 [STAC_D965_5ST] = "5stack",
1508 [STAC_DELL_3ST] = "dell-3stack",
1509 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001510};
1511
1512static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1513 /* SigmaTel reference board */
1514 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1515 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001516 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1518 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001519 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001520 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1521 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1522 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1524 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1530 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001536 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001537 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001539 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001541 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001550 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1554 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001560 {} /* terminator */
1561};
1562
Matt Porterf3302a52006-07-31 12:49:34 +02001563static unsigned int ref9205_pin_configs[12] = {
1564 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001565 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001566 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001567};
1568
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001569/*
1570 STAC 9205 pin configs for
1571 102801F1
1572 102801F2
1573 102801FC
1574 102801FD
1575 10280204
1576 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001577 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001578*/
1579static unsigned int dell_9205_m42_pin_configs[12] = {
1580 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1581 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1582 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1583};
1584
1585/*
1586 STAC 9205 pin configs for
1587 102801F9
1588 102801FA
1589 102801FE
1590 102801FF (Dell Precision M4300)
1591 10280206
1592 10280200
1593 10280201
1594*/
1595static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001596 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1597 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1598 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1599};
1600
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001601static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001602 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1603 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1604 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1605};
1606
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001607static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001608 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001609 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1610 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1611 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001612};
1613
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001614static const char *stac9205_models[STAC_9205_MODELS] = {
1615 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001616 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001617 [STAC_9205_DELL_M43] = "dell-m43",
1618 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001619};
1620
1621static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1622 /* SigmaTel reference board */
1623 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1624 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001625 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1626 "unknown Dell", STAC_9205_DELL_M42),
1627 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1628 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001629 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001630 "Dell Precision", STAC_9205_DELL_M43),
1631 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1632 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001633 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1634 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001635 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1636 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001637 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1638 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001639 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1640 "unknown Dell", STAC_9205_DELL_M42),
1641 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1642 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001643 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1644 "Dell Precision", STAC_9205_DELL_M43),
1645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001646 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1648 "Dell Precision", STAC_9205_DELL_M43),
1649 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1650 "Dell Inspiron", STAC_9205_DELL_M44),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1652 "Dell Inspiron", STAC_9205_DELL_M44),
1653 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1654 "Dell Inspiron", STAC_9205_DELL_M44),
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1656 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001657 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1658 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001659 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1660 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001661 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1662 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001663 {} /* terminator */
1664};
1665
Richard Fish11b44bb2006-08-23 18:31:34 +02001666static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1667{
1668 int i;
1669 struct sigmatel_spec *spec = codec->spec;
1670
1671 if (! spec->bios_pin_configs) {
1672 spec->bios_pin_configs = kcalloc(spec->num_pins,
1673 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1674 if (! spec->bios_pin_configs)
1675 return -ENOMEM;
1676 }
1677
1678 for (i = 0; i < spec->num_pins; i++) {
1679 hda_nid_t nid = spec->pin_nids[i];
1680 unsigned int pin_cfg;
1681
1682 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1683 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1684 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1685 nid, pin_cfg);
1686 spec->bios_pin_configs[i] = pin_cfg;
1687 }
1688
1689 return 0;
1690}
1691
Matthew Ranostay87d48362007-07-17 11:52:24 +02001692static void stac92xx_set_config_reg(struct hda_codec *codec,
1693 hda_nid_t pin_nid, unsigned int pin_config)
1694{
1695 int i;
1696 snd_hda_codec_write(codec, pin_nid, 0,
1697 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1698 pin_config & 0x000000ff);
1699 snd_hda_codec_write(codec, pin_nid, 0,
1700 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1701 (pin_config & 0x0000ff00) >> 8);
1702 snd_hda_codec_write(codec, pin_nid, 0,
1703 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1704 (pin_config & 0x00ff0000) >> 16);
1705 snd_hda_codec_write(codec, pin_nid, 0,
1706 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1707 pin_config >> 24);
1708 i = snd_hda_codec_read(codec, pin_nid, 0,
1709 AC_VERB_GET_CONFIG_DEFAULT,
1710 0x00);
1711 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1712 pin_nid, i);
1713}
1714
Matt2f2f4252005-04-13 14:45:30 +02001715static void stac92xx_set_config_regs(struct hda_codec *codec)
1716{
1717 int i;
1718 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001719
Matthew Ranostay87d48362007-07-17 11:52:24 +02001720 if (!spec->pin_configs)
1721 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001722
Matthew Ranostay87d48362007-07-17 11:52:24 +02001723 for (i = 0; i < spec->num_pins; i++)
1724 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1725 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001726}
Matt2f2f4252005-04-13 14:45:30 +02001727
Matt2f2f4252005-04-13 14:45:30 +02001728/*
1729 * Analog playback callbacks
1730 */
1731static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1732 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001733 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001734{
1735 struct sigmatel_spec *spec = codec->spec;
1736 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1737}
1738
1739static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1740 struct hda_codec *codec,
1741 unsigned int stream_tag,
1742 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001743 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001744{
1745 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001746 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001747}
1748
1749static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1750 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001751 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001752{
1753 struct sigmatel_spec *spec = codec->spec;
1754 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1755}
1756
1757/*
Mattdabbed62005-06-14 10:19:34 +02001758 * Digital playback callbacks
1759 */
1760static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1761 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001762 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001763{
1764 struct sigmatel_spec *spec = codec->spec;
1765 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1766}
1767
1768static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1769 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001770 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001771{
1772 struct sigmatel_spec *spec = codec->spec;
1773 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1774}
1775
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001776static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1777 struct hda_codec *codec,
1778 unsigned int stream_tag,
1779 unsigned int format,
1780 struct snd_pcm_substream *substream)
1781{
1782 struct sigmatel_spec *spec = codec->spec;
1783 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1784 stream_tag, format, substream);
1785}
1786
Mattdabbed62005-06-14 10:19:34 +02001787
1788/*
Matt2f2f4252005-04-13 14:45:30 +02001789 * Analog capture callbacks
1790 */
1791static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1792 struct hda_codec *codec,
1793 unsigned int stream_tag,
1794 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001795 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001796{
1797 struct sigmatel_spec *spec = codec->spec;
1798
1799 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1800 stream_tag, 0, format);
1801 return 0;
1802}
1803
1804static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1805 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001806 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001807{
1808 struct sigmatel_spec *spec = codec->spec;
1809
1810 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1811 return 0;
1812}
1813
Mattdabbed62005-06-14 10:19:34 +02001814static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1815 .substreams = 1,
1816 .channels_min = 2,
1817 .channels_max = 2,
1818 /* NID is set in stac92xx_build_pcms */
1819 .ops = {
1820 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001821 .close = stac92xx_dig_playback_pcm_close,
1822 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001823 },
1824};
1825
1826static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1827 .substreams = 1,
1828 .channels_min = 2,
1829 .channels_max = 2,
1830 /* NID is set in stac92xx_build_pcms */
1831};
1832
Matt2f2f4252005-04-13 14:45:30 +02001833static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1834 .substreams = 1,
1835 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001836 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001837 .nid = 0x02, /* NID to query formats and rates */
1838 .ops = {
1839 .open = stac92xx_playback_pcm_open,
1840 .prepare = stac92xx_playback_pcm_prepare,
1841 .cleanup = stac92xx_playback_pcm_cleanup
1842 },
1843};
1844
Matt Porter3cc08dc2006-01-23 15:27:49 +01001845static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1846 .substreams = 1,
1847 .channels_min = 2,
1848 .channels_max = 2,
1849 .nid = 0x06, /* NID to query formats and rates */
1850 .ops = {
1851 .open = stac92xx_playback_pcm_open,
1852 .prepare = stac92xx_playback_pcm_prepare,
1853 .cleanup = stac92xx_playback_pcm_cleanup
1854 },
1855};
1856
Matt2f2f4252005-04-13 14:45:30 +02001857static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001858 .channels_min = 2,
1859 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001860 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001861 .ops = {
1862 .prepare = stac92xx_capture_pcm_prepare,
1863 .cleanup = stac92xx_capture_pcm_cleanup
1864 },
1865};
1866
1867static int stac92xx_build_pcms(struct hda_codec *codec)
1868{
1869 struct sigmatel_spec *spec = codec->spec;
1870 struct hda_pcm *info = spec->pcm_rec;
1871
1872 codec->num_pcms = 1;
1873 codec->pcm_info = info;
1874
Mattc7d4b2f2005-06-27 14:59:41 +02001875 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001876 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001877 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001878 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001879 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001880
1881 if (spec->alt_switch) {
1882 codec->num_pcms++;
1883 info++;
1884 info->name = "STAC92xx Analog Alt";
1885 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1886 }
Matt2f2f4252005-04-13 14:45:30 +02001887
Mattdabbed62005-06-14 10:19:34 +02001888 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1889 codec->num_pcms++;
1890 info++;
1891 info->name = "STAC92xx Digital";
1892 if (spec->multiout.dig_out_nid) {
1893 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1894 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1895 }
1896 if (spec->dig_in_nid) {
1897 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1898 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1899 }
1900 }
1901
Matt2f2f4252005-04-13 14:45:30 +02001902 return 0;
1903}
1904
Takashi Iwaic960a032006-03-23 17:06:28 +01001905static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1906{
1907 unsigned int pincap = snd_hda_param_read(codec, nid,
1908 AC_PAR_PIN_CAP);
1909 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1910 if (pincap & AC_PINCAP_VREF_100)
1911 return AC_PINCTL_VREF_100;
1912 if (pincap & AC_PINCAP_VREF_80)
1913 return AC_PINCTL_VREF_80;
1914 if (pincap & AC_PINCAP_VREF_50)
1915 return AC_PINCTL_VREF_50;
1916 if (pincap & AC_PINCAP_VREF_GRD)
1917 return AC_PINCTL_VREF_GRD;
1918 return 0;
1919}
1920
Matt Porter403d1942005-11-29 15:00:51 +01001921static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1922
1923{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001924 snd_hda_codec_write_cache(codec, nid, 0,
1925 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001926}
1927
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001928#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001929
1930static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1931{
1932 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1933 struct sigmatel_spec *spec = codec->spec;
1934 int io_idx = kcontrol-> private_value & 0xff;
1935
1936 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1937 return 0;
1938}
1939
1940static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1941{
1942 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1943 struct sigmatel_spec *spec = codec->spec;
1944 hda_nid_t nid = kcontrol->private_value >> 8;
1945 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001946 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001947
1948 spec->io_switch[io_idx] = val;
1949
1950 if (val)
1951 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001952 else {
1953 unsigned int pinctl = AC_PINCTL_IN_EN;
1954 if (io_idx) /* set VREF for mic */
1955 pinctl |= stac92xx_get_vref(codec, nid);
1956 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1957 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001958
1959 /* check the auto-mute again: we need to mute/unmute the speaker
1960 * appropriately according to the pin direction
1961 */
1962 if (spec->hp_detect)
1963 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1964
Matt Porter403d1942005-11-29 15:00:51 +01001965 return 1;
1966}
1967
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001968#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1969
1970static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1971 struct snd_ctl_elem_value *ucontrol)
1972{
1973 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1974 struct sigmatel_spec *spec = codec->spec;
1975
1976 ucontrol->value.integer.value[0] = spec->clfe_swap;
1977 return 0;
1978}
1979
1980static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1981 struct snd_ctl_elem_value *ucontrol)
1982{
1983 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1984 struct sigmatel_spec *spec = codec->spec;
1985 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001986 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001987
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001988 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001989 return 0;
1990
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001991 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001992
1993 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1994 spec->clfe_swap ? 0x4 : 0x0);
1995
1996 return 1;
1997}
1998
Matt Porter403d1942005-11-29 15:00:51 +01001999#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2000 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2001 .name = xname, \
2002 .index = 0, \
2003 .info = stac92xx_io_switch_info, \
2004 .get = stac92xx_io_switch_get, \
2005 .put = stac92xx_io_switch_put, \
2006 .private_value = xpval, \
2007 }
2008
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002009#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2010 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2011 .name = xname, \
2012 .index = 0, \
2013 .info = stac92xx_clfe_switch_info, \
2014 .get = stac92xx_clfe_switch_get, \
2015 .put = stac92xx_clfe_switch_put, \
2016 .private_value = xpval, \
2017 }
Matt Porter403d1942005-11-29 15:00:51 +01002018
Mattc7d4b2f2005-06-27 14:59:41 +02002019enum {
2020 STAC_CTL_WIDGET_VOL,
2021 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002022 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002023 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002024 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002025};
2026
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002027static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002028 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2029 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002030 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002031 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002032 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002033};
2034
2035/* add dynamic controls */
2036static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2037{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002038 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002039
2040 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2041 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2042
2043 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2044 if (! knew)
2045 return -ENOMEM;
2046 if (spec->kctl_alloc) {
2047 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2048 kfree(spec->kctl_alloc);
2049 }
2050 spec->kctl_alloc = knew;
2051 spec->num_kctl_alloc = num;
2052 }
2053
2054 knew = &spec->kctl_alloc[spec->num_kctl_used];
2055 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002056 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002057 if (! knew->name)
2058 return -ENOMEM;
2059 knew->private_value = val;
2060 spec->num_kctl_used++;
2061 return 0;
2062}
2063
Matt Porter403d1942005-11-29 15:00:51 +01002064/* flag inputs as additional dynamic lineouts */
2065static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2066{
2067 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002068 unsigned int wcaps, wtype;
2069 int i, num_dacs = 0;
2070
2071 /* use the wcaps cache to count all DACs available for line-outs */
2072 for (i = 0; i < codec->num_nodes; i++) {
2073 wcaps = codec->wcaps[i];
2074 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002075
Steve Longerbeam7b043892007-05-03 20:50:03 +02002076 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2077 num_dacs++;
2078 }
Matt Porter403d1942005-11-29 15:00:51 +01002079
Steve Longerbeam7b043892007-05-03 20:50:03 +02002080 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2081
Matt Porter403d1942005-11-29 15:00:51 +01002082 switch (cfg->line_outs) {
2083 case 3:
2084 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002085 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002086 cfg->line_out_pins[cfg->line_outs] =
2087 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002088 spec->line_switch = 1;
2089 cfg->line_outs++;
2090 }
2091 break;
2092 case 2:
2093 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002094 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002095 cfg->line_out_pins[cfg->line_outs] =
2096 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002097 spec->line_switch = 1;
2098 cfg->line_outs++;
2099 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002100 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002101 cfg->line_out_pins[cfg->line_outs] =
2102 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002103 spec->mic_switch = 1;
2104 cfg->line_outs++;
2105 }
2106 break;
2107 case 1:
2108 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002109 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002110 cfg->line_out_pins[cfg->line_outs] =
2111 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002112 spec->line_switch = 1;
2113 cfg->line_outs++;
2114 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002115 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002116 cfg->line_out_pins[cfg->line_outs] =
2117 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002118 spec->mic_switch = 1;
2119 cfg->line_outs++;
2120 }
2121 break;
2122 }
2123
2124 return 0;
2125}
2126
Steve Longerbeam7b043892007-05-03 20:50:03 +02002127
2128static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2129{
2130 int i;
2131
2132 for (i = 0; i < spec->multiout.num_dacs; i++) {
2133 if (spec->multiout.dac_nids[i] == nid)
2134 return 1;
2135 }
2136
2137 return 0;
2138}
2139
Matt Porter3cc08dc2006-01-23 15:27:49 +01002140/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002141 * Fill in the dac_nids table from the parsed pin configuration
2142 * This function only works when every pin in line_out_pins[]
2143 * contains atleast one DAC in its connection list. Some 92xx
2144 * codecs are not connected directly to a DAC, such as the 9200
2145 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002146 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002147static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002148 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002149{
2150 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002151 int i, j, conn_len = 0;
2152 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2153 unsigned int wcaps, wtype;
2154
Mattc7d4b2f2005-06-27 14:59:41 +02002155 for (i = 0; i < cfg->line_outs; i++) {
2156 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002157 conn_len = snd_hda_get_connections(codec, nid, conn,
2158 HDA_MAX_CONNECTIONS);
2159 for (j = 0; j < conn_len; j++) {
2160 wcaps = snd_hda_param_read(codec, conn[j],
2161 AC_PAR_AUDIO_WIDGET_CAP);
2162 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002163 if (wtype != AC_WID_AUD_OUT ||
2164 (wcaps & AC_WCAP_DIGITAL))
2165 continue;
2166 /* conn[j] is a DAC routed to this line-out */
2167 if (!is_in_dac_nids(spec, conn[j]))
2168 break;
2169 }
2170
2171 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002172 if (spec->multiout.num_dacs > 0) {
2173 /* we have already working output pins,
2174 * so let's drop the broken ones again
2175 */
2176 cfg->line_outs = spec->multiout.num_dacs;
2177 break;
2178 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002179 /* error out, no available DAC found */
2180 snd_printk(KERN_ERR
2181 "%s: No available DAC for pin 0x%x\n",
2182 __func__, nid);
2183 return -ENODEV;
2184 }
2185
2186 spec->multiout.dac_nids[i] = conn[j];
2187 spec->multiout.num_dacs++;
2188 if (conn_len > 1) {
2189 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002190 snd_hda_codec_write_cache(codec, nid, 0,
2191 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002192
2193 }
Mattc7d4b2f2005-06-27 14:59:41 +02002194 }
2195
Steve Longerbeam7b043892007-05-03 20:50:03 +02002196 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2197 spec->multiout.num_dacs,
2198 spec->multiout.dac_nids[0],
2199 spec->multiout.dac_nids[1],
2200 spec->multiout.dac_nids[2],
2201 spec->multiout.dac_nids[3],
2202 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002203 return 0;
2204}
2205
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002206/* create volume control/switch for the given prefx type */
2207static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2208{
2209 char name[32];
2210 int err;
2211
2212 sprintf(name, "%s Playback Volume", pfx);
2213 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2214 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2215 if (err < 0)
2216 return err;
2217 sprintf(name, "%s Playback Switch", pfx);
2218 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2219 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2220 if (err < 0)
2221 return err;
2222 return 0;
2223}
2224
Mattc7d4b2f2005-06-27 14:59:41 +02002225/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002226static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002227 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002228{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002229 static const char *chname[4] = {
2230 "Front", "Surround", NULL /*CLFE*/, "Side"
2231 };
Mattc7d4b2f2005-06-27 14:59:41 +02002232 hda_nid_t nid;
2233 int i, err;
2234
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002235 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002236 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002237
2238
Mattc7d4b2f2005-06-27 14:59:41 +02002239 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002240 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002241 continue;
2242
2243 nid = spec->multiout.dac_nids[i];
2244
2245 if (i == 2) {
2246 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002247 err = create_controls(spec, "Center", nid, 1);
2248 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002249 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002250 err = create_controls(spec, "LFE", nid, 2);
2251 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002252 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002253
2254 wid_caps = get_wcaps(codec, nid);
2255
2256 if (wid_caps & AC_WCAP_LR_SWAP) {
2257 err = stac92xx_add_control(spec,
2258 STAC_CTL_WIDGET_CLFE_SWITCH,
2259 "Swap Center/LFE Playback Switch", nid);
2260
2261 if (err < 0)
2262 return err;
2263 }
2264
Mattc7d4b2f2005-06-27 14:59:41 +02002265 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002266 err = create_controls(spec, chname[i], nid, 3);
2267 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002268 return err;
2269 }
2270 }
2271
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002272 if (spec->line_switch) {
2273 nid = cfg->input_pins[AUTO_PIN_LINE];
2274 pincap = snd_hda_param_read(codec, nid,
2275 AC_PAR_PIN_CAP);
2276 if (pincap & AC_PINCAP_OUT) {
2277 err = stac92xx_add_control(spec,
2278 STAC_CTL_WIDGET_IO_SWITCH,
2279 "Line In as Output Switch", nid << 8);
2280 if (err < 0)
2281 return err;
2282 }
2283 }
Matt Porter403d1942005-11-29 15:00:51 +01002284
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002285 if (spec->mic_switch) {
2286 nid = cfg->input_pins[AUTO_PIN_MIC];
2287 pincap = snd_hda_param_read(codec, nid,
2288 AC_PAR_PIN_CAP);
2289 if (pincap & AC_PINCAP_OUT) {
2290 err = stac92xx_add_control(spec,
2291 STAC_CTL_WIDGET_IO_SWITCH,
2292 "Mic as Output Switch", (nid << 8) | 1);
2293 if (err < 0)
2294 return err;
2295 }
2296 }
Matt Porter403d1942005-11-29 15:00:51 +01002297
Mattc7d4b2f2005-06-27 14:59:41 +02002298 return 0;
2299}
2300
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002301static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2302{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002303 if (is_in_dac_nids(spec, nid))
2304 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002305 if (spec->multiout.hp_nid == nid)
2306 return 1;
2307 return 0;
2308}
2309
2310static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2311{
2312 if (!spec->multiout.hp_nid)
2313 spec->multiout.hp_nid = nid;
2314 else if (spec->multiout.num_dacs > 4) {
2315 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2316 return 1;
2317 } else {
2318 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2319 spec->multiout.num_dacs++;
2320 }
2321 return 0;
2322}
2323
2324/* add playback controls for Speaker and HP outputs */
2325static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2326 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002327{
2328 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002329 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002330 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002331
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002332 old_num_dacs = spec->multiout.num_dacs;
2333 for (i = 0; i < cfg->hp_outs; i++) {
2334 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2335 if (wid_caps & AC_WCAP_UNSOL_CAP)
2336 spec->hp_detect = 1;
2337 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2338 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2339 if (check_in_dac_nids(spec, nid))
2340 nid = 0;
2341 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002342 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002343 add_spec_dacs(spec, nid);
2344 }
2345 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002346 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002347 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2348 if (check_in_dac_nids(spec, nid))
2349 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002350 if (! nid)
2351 continue;
2352 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002353 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002354 for (i = 0; i < cfg->line_outs; i++) {
2355 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2356 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2357 if (check_in_dac_nids(spec, nid))
2358 nid = 0;
2359 if (! nid)
2360 continue;
2361 add_spec_dacs(spec, nid);
2362 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002363 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2364 static const char *pfxs[] = {
2365 "Speaker", "External Speaker", "Speaker2",
2366 };
2367 err = create_controls(spec, pfxs[i - old_num_dacs],
2368 spec->multiout.dac_nids[i], 3);
2369 if (err < 0)
2370 return err;
2371 }
2372 if (spec->multiout.hp_nid) {
2373 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002374 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002375 pfx = "Master";
2376 else
2377 pfx = "Headphone";
2378 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2379 if (err < 0)
2380 return err;
2381 }
Mattc7d4b2f2005-06-27 14:59:41 +02002382
2383 return 0;
2384}
2385
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002386/* labels for mono mux outputs */
2387static const char *stac92xx_mono_labels[3] = {
2388 "DAC0", "DAC1", "Mixer"
2389};
2390
2391/* create mono mux for mono out on capable codecs */
2392static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2393{
2394 struct sigmatel_spec *spec = codec->spec;
2395 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2396 int i, num_cons;
2397 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2398
2399 num_cons = snd_hda_get_connections(codec,
2400 spec->mono_nid,
2401 con_lst,
2402 HDA_MAX_NUM_INPUTS);
2403 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2404 return -EINVAL;
2405
2406 for (i = 0; i < num_cons; i++) {
2407 mono_mux->items[mono_mux->num_items].label =
2408 stac92xx_mono_labels[i];
2409 mono_mux->items[mono_mux->num_items].index = i;
2410 mono_mux->num_items++;
2411 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002412
2413 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2414 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002415}
2416
Matt Porter8b657272006-10-26 17:12:59 +02002417/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002418static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002419 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2420 "Digital Mic 3", "Digital Mic 4"
2421};
2422
2423/* create playback/capture controls for input pins on dmic capable codecs */
2424static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2425 const struct auto_pin_cfg *cfg)
2426{
2427 struct sigmatel_spec *spec = codec->spec;
2428 struct hda_input_mux *dimux = &spec->private_dimux;
2429 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002430 int err, i, j;
2431 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002432
2433 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2434 dimux->items[dimux->num_items].index = 0;
2435 dimux->num_items++;
2436
2437 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002438 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002439 int index;
2440 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002441 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002442 unsigned int def_conf;
2443
2444 def_conf = snd_hda_codec_read(codec,
2445 spec->dmic_nids[i],
2446 0,
2447 AC_VERB_GET_CONFIG_DEFAULT,
2448 0);
2449 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2450 continue;
2451
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002452 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002453 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002454 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002455 con_lst,
2456 HDA_MAX_NUM_INPUTS);
2457 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002458 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002459 index = j;
2460 goto found;
2461 }
2462 continue;
2463found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002464 wcaps = get_wcaps(codec, nid);
2465
2466 if (wcaps & AC_WCAP_OUT_AMP) {
2467 sprintf(name, "%s Capture Volume",
2468 stac92xx_dmic_labels[dimux->num_items]);
2469
2470 err = stac92xx_add_control(spec,
2471 STAC_CTL_WIDGET_VOL,
2472 name,
2473 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2474 if (err < 0)
2475 return err;
2476 }
2477
Matt Porter8b657272006-10-26 17:12:59 +02002478 dimux->items[dimux->num_items].label =
2479 stac92xx_dmic_labels[dimux->num_items];
2480 dimux->items[dimux->num_items].index = index;
2481 dimux->num_items++;
2482 }
2483
2484 return 0;
2485}
2486
Mattc7d4b2f2005-06-27 14:59:41 +02002487/* create playback/capture controls for input pins */
2488static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2489{
2490 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002491 struct hda_input_mux *imux = &spec->private_imux;
2492 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2493 int i, j, k;
2494
2495 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002496 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002497
Takashi Iwai314634b2006-09-21 11:56:18 +02002498 if (!cfg->input_pins[i])
2499 continue;
2500 index = -1;
2501 for (j = 0; j < spec->num_muxes; j++) {
2502 int num_cons;
2503 num_cons = snd_hda_get_connections(codec,
2504 spec->mux_nids[j],
2505 con_lst,
2506 HDA_MAX_NUM_INPUTS);
2507 for (k = 0; k < num_cons; k++)
2508 if (con_lst[k] == cfg->input_pins[i]) {
2509 index = k;
2510 goto found;
2511 }
Mattc7d4b2f2005-06-27 14:59:41 +02002512 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002513 continue;
2514 found:
2515 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2516 imux->items[imux->num_items].index = index;
2517 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002518 }
2519
Steve Longerbeam7b043892007-05-03 20:50:03 +02002520 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002521 /*
2522 * Set the current input for the muxes.
2523 * The STAC9221 has two input muxes with identical source
2524 * NID lists. Hopefully this won't get confused.
2525 */
2526 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002527 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2528 AC_VERB_SET_CONNECT_SEL,
2529 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002530 }
2531 }
2532
Mattc7d4b2f2005-06-27 14:59:41 +02002533 return 0;
2534}
2535
Mattc7d4b2f2005-06-27 14:59:41 +02002536static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2537{
2538 struct sigmatel_spec *spec = codec->spec;
2539 int i;
2540
2541 for (i = 0; i < spec->autocfg.line_outs; i++) {
2542 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2543 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2544 }
2545}
2546
2547static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2548{
2549 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002550 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002551
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002552 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2553 hda_nid_t pin;
2554 pin = spec->autocfg.hp_pins[i];
2555 if (pin) /* connect to front */
2556 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2557 }
2558 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2559 hda_nid_t pin;
2560 pin = spec->autocfg.speaker_pins[i];
2561 if (pin) /* connect to front */
2562 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2563 }
Mattc7d4b2f2005-06-27 14:59:41 +02002564}
2565
Matt Porter3cc08dc2006-01-23 15:27:49 +01002566static 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 +02002567{
2568 struct sigmatel_spec *spec = codec->spec;
2569 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002570 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002571
Matt Porter8b657272006-10-26 17:12:59 +02002572 if ((err = snd_hda_parse_pin_def_config(codec,
2573 &spec->autocfg,
2574 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002575 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002576 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002577 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002578
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002579 /* If we have no real line-out pin and multiple hp-outs, HPs should
2580 * be set up as multi-channel outputs.
2581 */
2582 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2583 spec->autocfg.hp_outs > 1) {
2584 /* Copy hp_outs to line_outs, backup line_outs in
2585 * speaker_outs so that the following routines can handle
2586 * HP pins as primary outputs.
2587 */
2588 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2589 sizeof(spec->autocfg.line_out_pins));
2590 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2591 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2592 sizeof(spec->autocfg.hp_pins));
2593 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2594 hp_speaker_swap = 1;
2595 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002596 if (spec->autocfg.mono_out_pin) {
2597 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2598 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2599 u32 caps = query_amp_caps(codec,
2600 spec->autocfg.mono_out_pin, dir);
2601 hda_nid_t conn_list[1];
2602
2603 /* get the mixer node and then the mono mux if it exists */
2604 if (snd_hda_get_connections(codec,
2605 spec->autocfg.mono_out_pin, conn_list, 1) &&
2606 snd_hda_get_connections(codec, conn_list[0],
2607 conn_list, 1)) {
2608
2609 int wcaps = get_wcaps(codec, conn_list[0]);
2610 int wid_type = (wcaps & AC_WCAP_TYPE)
2611 >> AC_WCAP_TYPE_SHIFT;
2612 /* LR swap check, some stac925x have a mux that
2613 * changes the DACs output path instead of the
2614 * mono-mux path.
2615 */
2616 if (wid_type == AC_WID_AUD_SEL &&
2617 !(wcaps & AC_WCAP_LR_SWAP))
2618 spec->mono_nid = conn_list[0];
2619 }
2620 /* all mono outs have a least a mute/unmute switch */
2621 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2622 "Mono Playback Switch",
2623 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2624 1, 0, dir));
2625 if (err < 0)
2626 return err;
2627 /* check to see if there is volume support for the amp */
2628 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2629 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2630 "Mono Playback Volume",
2631 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2632 1, 0, dir));
2633 if (err < 0)
2634 return err;
2635 }
2636
2637 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2638 AC_PINCTL_OUT_EN);
2639 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002640
Matt Porter403d1942005-11-29 15:00:51 +01002641 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2642 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002643 if (spec->multiout.num_dacs == 0)
2644 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2645 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002646
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002647 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2648
2649 if (err < 0)
2650 return err;
2651
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002652 if (hp_speaker_swap == 1) {
2653 /* Restore the hp_outs and line_outs */
2654 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2655 sizeof(spec->autocfg.line_out_pins));
2656 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2657 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2658 sizeof(spec->autocfg.speaker_pins));
2659 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2660 memset(spec->autocfg.speaker_pins, 0,
2661 sizeof(spec->autocfg.speaker_pins));
2662 spec->autocfg.speaker_outs = 0;
2663 }
2664
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002665 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2666
2667 if (err < 0)
2668 return err;
2669
2670 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2671
2672 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002673 return err;
2674
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002675 if (spec->mono_nid > 0) {
2676 err = stac92xx_auto_create_mono_output_ctls(codec);
2677 if (err < 0)
2678 return err;
2679 }
2680
Matt Porter8b657272006-10-26 17:12:59 +02002681 if (spec->num_dmics > 0)
2682 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2683 &spec->autocfg)) < 0)
2684 return err;
2685
Mattc7d4b2f2005-06-27 14:59:41 +02002686 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002687 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002688 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002689
Takashi Iwai82bc9552006-03-21 11:24:42 +01002690 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002691 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002692 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002693 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002694
2695 if (spec->kctl_alloc)
2696 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2697
2698 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002699 if (!spec->dinput_mux)
2700 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002701 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002702
2703 return 1;
2704}
2705
Takashi Iwai82bc9552006-03-21 11:24:42 +01002706/* add playback controls for HP output */
2707static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2708 struct auto_pin_cfg *cfg)
2709{
2710 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002711 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002712 unsigned int wid_caps;
2713
2714 if (! pin)
2715 return 0;
2716
2717 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002718 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002719 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002720
2721 return 0;
2722}
2723
Richard Fish160ea0d2006-09-06 13:58:25 +02002724/* add playback controls for LFE output */
2725static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2726 struct auto_pin_cfg *cfg)
2727{
2728 struct sigmatel_spec *spec = codec->spec;
2729 int err;
2730 hda_nid_t lfe_pin = 0x0;
2731 int i;
2732
2733 /*
2734 * search speaker outs and line outs for a mono speaker pin
2735 * with an amp. If one is found, add LFE controls
2736 * for it.
2737 */
2738 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2739 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2740 unsigned long wcaps = get_wcaps(codec, pin);
2741 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2742 if (wcaps == AC_WCAP_OUT_AMP)
2743 /* found a mono speaker with an amp, must be lfe */
2744 lfe_pin = pin;
2745 }
2746
2747 /* if speaker_outs is 0, then speakers may be in line_outs */
2748 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2749 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2750 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2751 unsigned long cfg;
2752 cfg = snd_hda_codec_read(codec, pin, 0,
2753 AC_VERB_GET_CONFIG_DEFAULT,
2754 0x00);
2755 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2756 unsigned long wcaps = get_wcaps(codec, pin);
2757 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2758 if (wcaps == AC_WCAP_OUT_AMP)
2759 /* found a mono speaker with an amp,
2760 must be lfe */
2761 lfe_pin = pin;
2762 }
2763 }
2764 }
2765
2766 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002767 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002768 if (err < 0)
2769 return err;
2770 }
2771
2772 return 0;
2773}
2774
Mattc7d4b2f2005-06-27 14:59:41 +02002775static int stac9200_parse_auto_config(struct hda_codec *codec)
2776{
2777 struct sigmatel_spec *spec = codec->spec;
2778 int err;
2779
Kailang Yangdf694da2005-12-05 19:42:22 +01002780 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002781 return err;
2782
2783 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2784 return err;
2785
Takashi Iwai82bc9552006-03-21 11:24:42 +01002786 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2787 return err;
2788
Richard Fish160ea0d2006-09-06 13:58:25 +02002789 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2790 return err;
2791
Takashi Iwai82bc9552006-03-21 11:24:42 +01002792 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002793 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002794 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002795 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002796
2797 if (spec->kctl_alloc)
2798 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2799
2800 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002801 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002802
2803 return 1;
2804}
2805
Sam Revitch62fe78e2006-05-10 15:09:17 +02002806/*
2807 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2808 * funky external mute control using GPIO pins.
2809 */
2810
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002811static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002812 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002813{
2814 unsigned int gpiostate, gpiomask, gpiodir;
2815
2816 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2817 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002818 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002819
2820 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2821 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002822 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002823
2824 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2825 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002826 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002827
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002828 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002829 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2830
2831 snd_hda_codec_write(codec, codec->afg, 0,
2832 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002833 snd_hda_codec_read(codec, codec->afg, 0,
2834 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002835
2836 msleep(1);
2837
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002838 snd_hda_codec_read(codec, codec->afg, 0,
2839 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002840}
2841
Takashi Iwai314634b2006-09-21 11:56:18 +02002842static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2843 unsigned int event)
2844{
2845 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002846 snd_hda_codec_write_cache(codec, nid, 0,
2847 AC_VERB_SET_UNSOLICITED_ENABLE,
2848 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002849}
2850
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002851static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2852{
2853 int i;
2854 for (i = 0; i < cfg->hp_outs; i++)
2855 if (cfg->hp_pins[i] == nid)
2856 return 1; /* nid is a HP-Out */
2857
2858 return 0; /* nid is not a HP-Out */
2859};
2860
Mattc7d4b2f2005-06-27 14:59:41 +02002861static int stac92xx_init(struct hda_codec *codec)
2862{
2863 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002864 struct auto_pin_cfg *cfg = &spec->autocfg;
2865 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002866
Mattc7d4b2f2005-06-27 14:59:41 +02002867 snd_hda_sequence_write(codec, spec->init);
2868
Takashi Iwai82bc9552006-03-21 11:24:42 +01002869 /* set up pins */
2870 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002871 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002872 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002873 enable_pin_detect(codec, cfg->hp_pins[i],
2874 STAC_HP_EVENT);
Takashi Iwai0a07aca2007-03-13 10:40:23 +01002875 /* force to enable the first line-out; the others are set up
2876 * in unsol_event
2877 */
2878 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2879 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002880 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002881 /* fake event to set up pins */
2882 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2883 } else {
2884 stac92xx_auto_init_multi_out(codec);
2885 stac92xx_auto_init_hp_out(codec);
2886 }
2887 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002888 hda_nid_t nid = cfg->input_pins[i];
2889 if (nid) {
2890 unsigned int pinctl = AC_PINCTL_IN_EN;
2891 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2892 pinctl |= stac92xx_get_vref(codec, nid);
2893 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2894 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002895 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002896 for (i = 0; i < spec->num_dmics; i++)
2897 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2898 AC_PINCTL_IN_EN);
2899 for (i = 0; i < spec->num_pwrs; i++) {
2900 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2901 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2902 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2903 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2904 /* outputs are only ports capable of power management
2905 * any attempts on powering down a input port cause the
2906 * referenced VREF to act quirky.
2907 */
2908 if (pinctl & AC_PINCTL_IN_EN)
2909 continue;
2910 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2911 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2912 }
Matt Porter8b657272006-10-26 17:12:59 +02002913
Takashi Iwai82bc9552006-03-21 11:24:42 +01002914 if (cfg->dig_out_pin)
2915 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2916 AC_PINCTL_OUT_EN);
2917 if (cfg->dig_in_pin)
2918 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2919 AC_PINCTL_IN_EN);
2920
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002921 stac_gpio_set(codec, spec->gpio_mask,
2922 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002923
Mattc7d4b2f2005-06-27 14:59:41 +02002924 return 0;
2925}
2926
Matt2f2f4252005-04-13 14:45:30 +02002927static void stac92xx_free(struct hda_codec *codec)
2928{
Mattc7d4b2f2005-06-27 14:59:41 +02002929 struct sigmatel_spec *spec = codec->spec;
2930 int i;
2931
2932 if (! spec)
2933 return;
2934
2935 if (spec->kctl_alloc) {
2936 for (i = 0; i < spec->num_kctl_used; i++)
2937 kfree(spec->kctl_alloc[i].name);
2938 kfree(spec->kctl_alloc);
2939 }
2940
Richard Fish11b44bb2006-08-23 18:31:34 +02002941 if (spec->bios_pin_configs)
2942 kfree(spec->bios_pin_configs);
2943
Mattc7d4b2f2005-06-27 14:59:41 +02002944 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002945}
2946
Matt4e550962005-07-04 17:51:39 +02002947static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2948 unsigned int flag)
2949{
2950 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2951 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002952
Takashi Iwaif9acba42007-05-29 18:01:06 +02002953 if (pin_ctl & AC_PINCTL_IN_EN) {
2954 /*
2955 * we need to check the current set-up direction of
2956 * shared input pins since they can be switched via
2957 * "xxx as Output" mixer switch
2958 */
2959 struct sigmatel_spec *spec = codec->spec;
2960 struct auto_pin_cfg *cfg = &spec->autocfg;
2961 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2962 spec->line_switch) ||
2963 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2964 spec->mic_switch))
2965 return;
2966 }
2967
Steve Longerbeam7b043892007-05-03 20:50:03 +02002968 /* if setting pin direction bits, clear the current
2969 direction bits first */
2970 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2971 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2972
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002973 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002974 AC_VERB_SET_PIN_WIDGET_CONTROL,
2975 pin_ctl | flag);
2976}
2977
2978static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2979 unsigned int flag)
2980{
2981 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2982 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002983 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002984 AC_VERB_SET_PIN_WIDGET_CONTROL,
2985 pin_ctl & ~flag);
2986}
2987
Jiang Zhe40c1d302007-11-12 13:05:16 +01002988static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02002989{
2990 if (!nid)
2991 return 0;
2992 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01002993 & (1 << 31)) {
2994 unsigned int pinctl;
2995 pinctl = snd_hda_codec_read(codec, nid, 0,
2996 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2997 if (pinctl & AC_PINCTL_IN_EN)
2998 return 0; /* mic- or line-input */
2999 else
3000 return 1; /* HP-output */
3001 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003002 return 0;
3003}
3004
3005static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003006{
3007 struct sigmatel_spec *spec = codec->spec;
3008 struct auto_pin_cfg *cfg = &spec->autocfg;
3009 int i, presence;
3010
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003011 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003012 if (spec->gpio_mute)
3013 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3014 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3015
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003016 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003017 if (presence)
3018 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003019 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003020 }
Matt4e550962005-07-04 17:51:39 +02003021
3022 if (presence) {
3023 /* disable lineouts, enable hp */
3024 for (i = 0; i < cfg->line_outs; i++)
3025 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3026 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003027 for (i = 0; i < cfg->speaker_outs; i++)
3028 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3029 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003030 } else {
3031 /* enable lineouts, disable hp */
3032 for (i = 0; i < cfg->line_outs; i++)
3033 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3034 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003035 for (i = 0; i < cfg->speaker_outs; i++)
3036 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3037 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003038 }
3039}
3040
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003041static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3042{
3043 struct sigmatel_spec *spec = codec->spec;
3044 hda_nid_t nid = spec->pwr_nids[idx];
3045 int presence, val;
3046 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3047 & 0x000000ff;
3048 presence = get_hp_pin_presence(codec, nid);
3049 idx = 1 << idx;
3050
3051 if (presence)
3052 val &= ~idx;
3053 else
3054 val |= idx;
3055
3056 /* power down unused output ports */
3057 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3058};
3059
Takashi Iwai314634b2006-09-21 11:56:18 +02003060static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3061{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003062 struct sigmatel_spec *spec = codec->spec;
3063 int idx = res >> 26 & 0x0f;
3064
3065 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003066 case STAC_HP_EVENT:
3067 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003068 /* fallthru */
3069 case STAC_PWR_EVENT:
3070 if (spec->num_pwrs > 0)
3071 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003072 }
3073}
3074
Takashi Iwaicb53c622007-08-10 17:21:45 +02003075#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003076static int stac92xx_resume(struct hda_codec *codec)
3077{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003078 struct sigmatel_spec *spec = codec->spec;
3079
Richard Fish11b44bb2006-08-23 18:31:34 +02003080 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003081 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003082 stac_gpio_set(codec, spec->gpio_mask,
3083 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003084 snd_hda_codec_resume_amp(codec);
3085 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003086 /* invoke unsolicited event to reset the HP state */
3087 if (spec->hp_detect)
3088 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003089 return 0;
3090}
3091#endif
3092
Matt2f2f4252005-04-13 14:45:30 +02003093static struct hda_codec_ops stac92xx_patch_ops = {
3094 .build_controls = stac92xx_build_controls,
3095 .build_pcms = stac92xx_build_pcms,
3096 .init = stac92xx_init,
3097 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003098 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003099#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003100 .resume = stac92xx_resume,
3101#endif
Matt2f2f4252005-04-13 14:45:30 +02003102};
3103
3104static int patch_stac9200(struct hda_codec *codec)
3105{
3106 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003107 int err;
Matt2f2f4252005-04-13 14:45:30 +02003108
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003109 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003110 if (spec == NULL)
3111 return -ENOMEM;
3112
3113 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003114 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003115 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003116 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3117 stac9200_models,
3118 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003119 if (spec->board_config < 0) {
3120 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3121 err = stac92xx_save_bios_config_regs(codec);
3122 if (err < 0) {
3123 stac92xx_free(codec);
3124 return err;
3125 }
3126 spec->pin_configs = spec->bios_pin_configs;
3127 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003128 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3129 stac92xx_set_config_regs(codec);
3130 }
Matt2f2f4252005-04-13 14:45:30 +02003131
3132 spec->multiout.max_channels = 2;
3133 spec->multiout.num_dacs = 1;
3134 spec->multiout.dac_nids = stac9200_dac_nids;
3135 spec->adc_nids = stac9200_adc_nids;
3136 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003137 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003138 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003139 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003140 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003141
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003142 if (spec->board_config == STAC_9200_GATEWAY)
3143 spec->init = stac9200_eapd_init;
3144 else
3145 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003146 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003147
3148 err = stac9200_parse_auto_config(codec);
3149 if (err < 0) {
3150 stac92xx_free(codec);
3151 return err;
3152 }
Matt2f2f4252005-04-13 14:45:30 +02003153
3154 codec->patch_ops = stac92xx_patch_ops;
3155
3156 return 0;
3157}
3158
Tobin Davis8e21c342007-01-08 11:04:17 +01003159static int patch_stac925x(struct hda_codec *codec)
3160{
3161 struct sigmatel_spec *spec;
3162 int err;
3163
3164 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3165 if (spec == NULL)
3166 return -ENOMEM;
3167
3168 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003169 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003170 spec->pin_nids = stac925x_pin_nids;
3171 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3172 stac925x_models,
3173 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003174 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003175 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003176 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3177 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003178 err = stac92xx_save_bios_config_regs(codec);
3179 if (err < 0) {
3180 stac92xx_free(codec);
3181 return err;
3182 }
3183 spec->pin_configs = spec->bios_pin_configs;
3184 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3185 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3186 stac92xx_set_config_regs(codec);
3187 }
3188
3189 spec->multiout.max_channels = 2;
3190 spec->multiout.num_dacs = 1;
3191 spec->multiout.dac_nids = stac925x_dac_nids;
3192 spec->adc_nids = stac925x_adc_nids;
3193 spec->mux_nids = stac925x_mux_nids;
3194 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003195 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003196 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003197 switch (codec->vendor_id) {
3198 case 0x83847632: /* STAC9202 */
3199 case 0x83847633: /* STAC9202D */
3200 case 0x83847636: /* STAC9251 */
3201 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003202 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003203 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01003204 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3205 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003206 break;
3207 default:
3208 spec->num_dmics = 0;
3209 break;
3210 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003211
3212 spec->init = stac925x_core_init;
3213 spec->mixer = stac925x_mixer;
3214
3215 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003216 if (!err) {
3217 if (spec->board_config < 0) {
3218 printk(KERN_WARNING "hda_codec: No auto-config is "
3219 "available, default to model=ref\n");
3220 spec->board_config = STAC_925x_REF;
3221 goto again;
3222 }
3223 err = -EINVAL;
3224 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003225 if (err < 0) {
3226 stac92xx_free(codec);
3227 return err;
3228 }
3229
3230 codec->patch_ops = stac92xx_patch_ops;
3231
3232 return 0;
3233}
3234
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003235static struct hda_input_mux stac92hd73xx_dmux = {
3236 .num_items = 4,
3237 .items = {
3238 { "Analog Inputs", 0x0b },
3239 { "CD", 0x08 },
3240 { "Digital Mic 1", 0x09 },
3241 { "Digital Mic 2", 0x0a },
3242 }
3243};
3244
3245static int patch_stac92hd73xx(struct hda_codec *codec)
3246{
3247 struct sigmatel_spec *spec;
3248 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3249 int err = 0;
3250
3251 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3252 if (spec == NULL)
3253 return -ENOMEM;
3254
3255 codec->spec = spec;
3256 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3257 spec->pin_nids = stac92hd73xx_pin_nids;
3258 spec->board_config = snd_hda_check_board_config(codec,
3259 STAC_92HD73XX_MODELS,
3260 stac92hd73xx_models,
3261 stac92hd73xx_cfg_tbl);
3262again:
3263 if (spec->board_config < 0) {
3264 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3265 " STAC92HD73XX, using BIOS defaults\n");
3266 err = stac92xx_save_bios_config_regs(codec);
3267 if (err < 0) {
3268 stac92xx_free(codec);
3269 return err;
3270 }
3271 spec->pin_configs = spec->bios_pin_configs;
3272 } else {
3273 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3274 stac92xx_set_config_regs(codec);
3275 }
3276
3277 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3278 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3279
3280 if (spec->multiout.num_dacs < 0) {
3281 printk(KERN_WARNING "hda_codec: Could not determine "
3282 "number of channels defaulting to DAC count\n");
3283 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3284 }
3285
3286 switch (spec->multiout.num_dacs) {
3287 case 0x3: /* 6 Channel */
3288 spec->mixer = stac92hd73xx_6ch_mixer;
3289 spec->init = stac92hd73xx_6ch_core_init;
3290 break;
3291 case 0x4: /* 8 Channel */
3292 spec->multiout.hp_nid = 0x18;
3293 spec->mixer = stac92hd73xx_8ch_mixer;
3294 spec->init = stac92hd73xx_8ch_core_init;
3295 break;
3296 case 0x5: /* 10 Channel */
3297 spec->multiout.hp_nid = 0x19;
3298 spec->mixer = stac92hd73xx_10ch_mixer;
3299 spec->init = stac92hd73xx_10ch_core_init;
3300 };
3301
3302 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3303 spec->aloopback_mask = 0x01;
3304 spec->aloopback_shift = 8;
3305
3306 spec->mux_nids = stac92hd73xx_mux_nids;
3307 spec->adc_nids = stac92hd73xx_adc_nids;
3308 spec->dmic_nids = stac92hd73xx_dmic_nids;
3309 spec->dmux_nids = stac92hd73xx_dmux_nids;
3310
3311 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3312 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3313 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai16970552007-12-18 18:05:52 +01003314 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003315 spec->dinput_mux = &stac92hd73xx_dmux;
3316 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003317 spec->gpio_mask = spec->gpio_dir = 0x1;
3318 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003319
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003320 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3321 spec->pwr_nids = stac92hd73xx_pwr_nids;
3322
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003323 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3324
3325 if (!err) {
3326 if (spec->board_config < 0) {
3327 printk(KERN_WARNING "hda_codec: No auto-config is "
3328 "available, default to model=ref\n");
3329 spec->board_config = STAC_92HD73XX_REF;
3330 goto again;
3331 }
3332 err = -EINVAL;
3333 }
3334
3335 if (err < 0) {
3336 stac92xx_free(codec);
3337 return err;
3338 }
3339
3340 codec->patch_ops = stac92xx_patch_ops;
3341
3342 return 0;
3343}
3344
Matthew Ranostaye035b842007-11-06 11:53:55 +01003345static int patch_stac92hd71bxx(struct hda_codec *codec)
3346{
3347 struct sigmatel_spec *spec;
3348 int err = 0;
3349
3350 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3351 if (spec == NULL)
3352 return -ENOMEM;
3353
3354 codec->spec = spec;
3355 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3356 spec->pin_nids = stac92hd71bxx_pin_nids;
3357 spec->board_config = snd_hda_check_board_config(codec,
3358 STAC_92HD71BXX_MODELS,
3359 stac92hd71bxx_models,
3360 stac92hd71bxx_cfg_tbl);
3361again:
3362 if (spec->board_config < 0) {
3363 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3364 " STAC92HD71BXX, using BIOS defaults\n");
3365 err = stac92xx_save_bios_config_regs(codec);
3366 if (err < 0) {
3367 stac92xx_free(codec);
3368 return err;
3369 }
3370 spec->pin_configs = spec->bios_pin_configs;
3371 } else {
3372 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3373 stac92xx_set_config_regs(codec);
3374 }
3375
Matthew Ranostay541eee82007-12-14 12:08:04 +01003376 switch (codec->vendor_id) {
3377 case 0x111d76b6: /* 4 Port without Analog Mixer */
3378 case 0x111d76b7:
3379 case 0x111d76b4: /* 6 Port without Analog Mixer */
3380 case 0x111d76b5:
3381 spec->mixer = stac92hd71bxx_mixer;
3382 spec->init = stac92hd71bxx_core_init;
3383 break;
3384 default:
3385 spec->mixer = stac92hd71bxx_analog_mixer;
3386 spec->init = stac92hd71bxx_analog_core_init;
3387 }
3388
3389 spec->aloopback_mask = 0x20;
3390 spec->aloopback_shift = 0;
3391
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003392 /* GPIO0 High = EAPD */
3393 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003394
Matthew Ranostaye035b842007-11-06 11:53:55 +01003395 spec->mux_nids = stac92hd71bxx_mux_nids;
3396 spec->adc_nids = stac92hd71bxx_adc_nids;
3397 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003398 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003399
3400 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3401 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3402 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai16970552007-12-18 18:05:52 +01003403 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003404
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003405 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3406 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3407
Matthew Ranostaye035b842007-11-06 11:53:55 +01003408 spec->multiout.num_dacs = 2;
3409 spec->multiout.hp_nid = 0x11;
3410 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3411
3412 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3413 if (!err) {
3414 if (spec->board_config < 0) {
3415 printk(KERN_WARNING "hda_codec: No auto-config is "
3416 "available, default to model=ref\n");
3417 spec->board_config = STAC_92HD71BXX_REF;
3418 goto again;
3419 }
3420 err = -EINVAL;
3421 }
3422
3423 if (err < 0) {
3424 stac92xx_free(codec);
3425 return err;
3426 }
3427
3428 codec->patch_ops = stac92xx_patch_ops;
3429
3430 return 0;
3431};
3432
Matt2f2f4252005-04-13 14:45:30 +02003433static int patch_stac922x(struct hda_codec *codec)
3434{
3435 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003436 int err;
Matt2f2f4252005-04-13 14:45:30 +02003437
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003438 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003439 if (spec == NULL)
3440 return -ENOMEM;
3441
3442 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003443 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003444 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003445 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3446 stac922x_models,
3447 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003448 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003449 spec->gpio_mask = spec->gpio_dir = 0x03;
3450 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003451 /* Intel Macs have all same PCI SSID, so we need to check
3452 * codec SSID to distinguish the exact models
3453 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003454 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003455 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003456
3457 case 0x106b0800:
3458 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003459 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003460 case 0x106b0600:
3461 case 0x106b0700:
3462 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003463 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003464 case 0x106b0e00:
3465 case 0x106b0f00:
3466 case 0x106b1600:
3467 case 0x106b1700:
3468 case 0x106b0200:
3469 case 0x106b1e00:
3470 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003471 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003472 case 0x106b1a00:
3473 case 0x00000100:
3474 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003475 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003476 case 0x106b0a00:
3477 case 0x106b2200:
3478 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003479 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003480 }
3481 }
3482
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003483 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003484 if (spec->board_config < 0) {
3485 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3486 "using BIOS defaults\n");
3487 err = stac92xx_save_bios_config_regs(codec);
3488 if (err < 0) {
3489 stac92xx_free(codec);
3490 return err;
3491 }
3492 spec->pin_configs = spec->bios_pin_configs;
3493 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003494 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3495 stac92xx_set_config_regs(codec);
3496 }
Matt2f2f4252005-04-13 14:45:30 +02003497
Matt2f2f4252005-04-13 14:45:30 +02003498 spec->adc_nids = stac922x_adc_nids;
3499 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003500 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003501 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003502 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003503 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003504
3505 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003506 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003507
3508 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003509
Matt Porter3cc08dc2006-01-23 15:27:49 +01003510 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003511 if (!err) {
3512 if (spec->board_config < 0) {
3513 printk(KERN_WARNING "hda_codec: No auto-config is "
3514 "available, default to model=ref\n");
3515 spec->board_config = STAC_D945_REF;
3516 goto again;
3517 }
3518 err = -EINVAL;
3519 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003520 if (err < 0) {
3521 stac92xx_free(codec);
3522 return err;
3523 }
3524
3525 codec->patch_ops = stac92xx_patch_ops;
3526
Takashi Iwai807a46362007-05-29 19:01:37 +02003527 /* Fix Mux capture level; max to 2 */
3528 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3529 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3530 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3531 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3532 (0 << AC_AMPCAP_MUTE_SHIFT));
3533
Matt Porter3cc08dc2006-01-23 15:27:49 +01003534 return 0;
3535}
3536
3537static int patch_stac927x(struct hda_codec *codec)
3538{
3539 struct sigmatel_spec *spec;
3540 int err;
3541
3542 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3543 if (spec == NULL)
3544 return -ENOMEM;
3545
3546 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003547 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003548 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003549 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3550 stac927x_models,
3551 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003552 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003553 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3554 if (spec->board_config < 0)
3555 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3556 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003557 err = stac92xx_save_bios_config_regs(codec);
3558 if (err < 0) {
3559 stac92xx_free(codec);
3560 return err;
3561 }
3562 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003563 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003564 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3565 stac92xx_set_config_regs(codec);
3566 }
3567
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003568 spec->adc_nids = stac927x_adc_nids;
3569 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3570 spec->mux_nids = stac927x_mux_nids;
3571 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
3572 spec->multiout.dac_nids = spec->dac_nids;
3573
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003574 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003575 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003576 case STAC_D965_5ST:
3577 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003578 spec->gpio_mask = spec->gpio_dir = 0x01;
3579 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003580 spec->num_dmics = 0;
3581
Tobin Davis93ed1502006-09-01 21:03:12 +02003582 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003583 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003584 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003585 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003586 /* correct the front output jack as a hp out */
3587 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003588 /* correct the front input jack as a mic */
3589 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3590 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003591 case STAC_DELL_3ST:
3592 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003593 spec->gpio_mask = spec->gpio_dir = 0x04;
3594 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003595 spec->dmic_nids = stac927x_dmic_nids;
3596 spec->num_dmics = STAC927X_NUM_DMICS;
3597
Tobin Davis93ed1502006-09-01 21:03:12 +02003598 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003599 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003600 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01003601 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003602 break;
3603 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003604 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003605 spec->gpio_mask = spec->gpio_dir = 0x1;
3606 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003607 spec->num_dmics = 0;
3608
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003609 spec->init = stac927x_core_init;
3610 spec->mixer = stac927x_mixer;
3611 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003612
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003613 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003614 spec->aloopback_mask = 0x40;
3615 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003616
Matt Porter3cc08dc2006-01-23 15:27:49 +01003617 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003618 if (!err) {
3619 if (spec->board_config < 0) {
3620 printk(KERN_WARNING "hda_codec: No auto-config is "
3621 "available, default to model=ref\n");
3622 spec->board_config = STAC_D965_REF;
3623 goto again;
3624 }
3625 err = -EINVAL;
3626 }
Mattc7d4b2f2005-06-27 14:59:41 +02003627 if (err < 0) {
3628 stac92xx_free(codec);
3629 return err;
3630 }
Matt2f2f4252005-04-13 14:45:30 +02003631
3632 codec->patch_ops = stac92xx_patch_ops;
3633
Takashi Iwai52987652008-01-16 16:09:47 +01003634 /*
3635 * !!FIXME!!
3636 * The STAC927x seem to require fairly long delays for certain
3637 * command sequences. With too short delays (even if the answer
3638 * is set to RIRB properly), it results in the silence output
3639 * on some hardwares like Dell.
3640 *
3641 * The below flag enables the longer delay (see get_response
3642 * in hda_intel.c).
3643 */
3644 codec->bus->needs_damn_long_delay = 1;
3645
Matt2f2f4252005-04-13 14:45:30 +02003646 return 0;
3647}
3648
Matt Porterf3302a52006-07-31 12:49:34 +02003649static int patch_stac9205(struct hda_codec *codec)
3650{
3651 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003652 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003653
3654 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3655 if (spec == NULL)
3656 return -ENOMEM;
3657
3658 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003659 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003660 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003661 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3662 stac9205_models,
3663 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003664 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003665 if (spec->board_config < 0) {
3666 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3667 err = stac92xx_save_bios_config_regs(codec);
3668 if (err < 0) {
3669 stac92xx_free(codec);
3670 return err;
3671 }
3672 spec->pin_configs = spec->bios_pin_configs;
3673 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003674 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3675 stac92xx_set_config_regs(codec);
3676 }
3677
3678 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003679 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003680 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003681 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003682 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003683 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003684 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai16970552007-12-18 18:05:52 +01003685 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003686 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003687
3688 spec->init = stac9205_core_init;
3689 spec->mixer = stac9205_mixer;
3690
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003691 spec->aloopback_mask = 0x40;
3692 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003693 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003694
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003695 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003696 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003697 /* Enable SPDIF in/out */
3698 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3699 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003700
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003701 /* Enable unsol response for GPIO4/Dock HP connection */
3702 snd_hda_codec_write(codec, codec->afg, 0,
3703 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3704 snd_hda_codec_write_cache(codec, codec->afg, 0,
3705 AC_VERB_SET_UNSOLICITED_ENABLE,
3706 (AC_USRSP_EN | STAC_HP_EVENT));
3707
3708 spec->gpio_dir = 0x0b;
3709 spec->gpio_mask = 0x1b;
3710 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003711 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003712 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003713 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003714 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003715 break;
3716 default:
3717 /* GPIO0 High = EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003718 spec->gpio_mask = spec->gpio_dir = 0x1;
3719 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003720 break;
3721 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003722
Matt Porterf3302a52006-07-31 12:49:34 +02003723 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003724 if (!err) {
3725 if (spec->board_config < 0) {
3726 printk(KERN_WARNING "hda_codec: No auto-config is "
3727 "available, default to model=ref\n");
3728 spec->board_config = STAC_9205_REF;
3729 goto again;
3730 }
3731 err = -EINVAL;
3732 }
Matt Porterf3302a52006-07-31 12:49:34 +02003733 if (err < 0) {
3734 stac92xx_free(codec);
3735 return err;
3736 }
3737
3738 codec->patch_ops = stac92xx_patch_ops;
3739
3740 return 0;
3741}
3742
Matt2f2f4252005-04-13 14:45:30 +02003743/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003744 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003745 */
3746
Guillaume Munch99ccc562006-08-16 19:35:12 +02003747/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003748static hda_nid_t vaio_dacs[] = { 0x2 };
3749#define VAIO_HP_DAC 0x5
3750static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3751static hda_nid_t vaio_mux_nids[] = { 0x15 };
3752
3753static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003754 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003755 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003756 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003757 { "Mic Jack", 0x1 },
3758 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003759 { "PCM", 0x3 },
3760 }
3761};
3762
3763static struct hda_verb vaio_init[] = {
3764 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003765 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003766 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3767 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3768 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3769 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003770 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003771 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3772 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3773 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3774 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3775 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3776 {}
3777};
3778
Guillaume Munch6d859062006-08-22 17:15:47 +02003779static struct hda_verb vaio_ar_init[] = {
3780 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3781 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3782 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3783 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3784/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3785 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003786 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003787 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3788 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3789/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3790 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3792 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3793 {}
3794};
3795
Takashi Iwaidb064e52006-03-16 16:04:58 +01003796/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003797static struct hda_bind_ctls vaio_bind_master_vol = {
3798 .ops = &snd_hda_bind_vol,
3799 .values = {
3800 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3801 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3802 0
3803 },
3804};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003805
3806/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003807static struct hda_bind_ctls vaio_bind_master_sw = {
3808 .ops = &snd_hda_bind_sw,
3809 .values = {
3810 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3811 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3812 0,
3813 },
3814};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003815
3816static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003817 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3818 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003819 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3820 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3821 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3822 {
3823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3824 .name = "Capture Source",
3825 .count = 1,
3826 .info = stac92xx_mux_enum_info,
3827 .get = stac92xx_mux_enum_get,
3828 .put = stac92xx_mux_enum_put,
3829 },
3830 {}
3831};
3832
Guillaume Munch6d859062006-08-22 17:15:47 +02003833static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003834 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3835 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003836 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3837 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3838 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3839 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3840 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3841 {
3842 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3843 .name = "Capture Source",
3844 .count = 1,
3845 .info = stac92xx_mux_enum_info,
3846 .get = stac92xx_mux_enum_get,
3847 .put = stac92xx_mux_enum_put,
3848 },
3849 {}
3850};
3851
3852static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003853 .build_controls = stac92xx_build_controls,
3854 .build_pcms = stac92xx_build_pcms,
3855 .init = stac92xx_init,
3856 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003857#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003858 .resume = stac92xx_resume,
3859#endif
3860};
3861
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003862static int stac9872_vaio_init(struct hda_codec *codec)
3863{
3864 int err;
3865
3866 err = stac92xx_init(codec);
3867 if (err < 0)
3868 return err;
3869 if (codec->patch_ops.unsol_event)
3870 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3871 return 0;
3872}
3873
3874static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3875{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003876 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003877 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3878 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3879 } else {
3880 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3881 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3882 }
3883}
3884
3885static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3886{
3887 switch (res >> 26) {
3888 case STAC_HP_EVENT:
3889 stac9872_vaio_hp_detect(codec, res);
3890 break;
3891 }
3892}
3893
3894static struct hda_codec_ops stac9872_vaio_patch_ops = {
3895 .build_controls = stac92xx_build_controls,
3896 .build_pcms = stac92xx_build_pcms,
3897 .init = stac9872_vaio_init,
3898 .free = stac92xx_free,
3899 .unsol_event = stac9872_vaio_unsol_event,
3900#ifdef CONFIG_PM
3901 .resume = stac92xx_resume,
3902#endif
3903};
3904
Guillaume Munch6d859062006-08-22 17:15:47 +02003905enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3906 CXD9872RD_VAIO,
3907 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3908 STAC9872AK_VAIO,
3909 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3910 STAC9872K_VAIO,
3911 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003912 CXD9872AKD_VAIO,
3913 STAC_9872_MODELS,
3914};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003915
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003916static const char *stac9872_models[STAC_9872_MODELS] = {
3917 [CXD9872RD_VAIO] = "vaio",
3918 [CXD9872AKD_VAIO] = "vaio-ar",
3919};
3920
3921static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3922 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3923 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3924 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003925 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003926 {}
3927};
3928
Guillaume Munch6d859062006-08-22 17:15:47 +02003929static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003930{
3931 struct sigmatel_spec *spec;
3932 int board_config;
3933
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003934 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3935 stac9872_models,
3936 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003937 if (board_config < 0)
3938 /* unknown config, let generic-parser do its job... */
3939 return snd_hda_parse_generic_codec(codec);
3940
3941 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3942 if (spec == NULL)
3943 return -ENOMEM;
3944
3945 codec->spec = spec;
3946 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003947 case CXD9872RD_VAIO:
3948 case STAC9872AK_VAIO:
3949 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003950 spec->mixer = vaio_mixer;
3951 spec->init = vaio_init;
3952 spec->multiout.max_channels = 2;
3953 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3954 spec->multiout.dac_nids = vaio_dacs;
3955 spec->multiout.hp_nid = VAIO_HP_DAC;
3956 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3957 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003958 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003959 spec->input_mux = &vaio_mux;
3960 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003961 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003962 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003963
3964 case CXD9872AKD_VAIO:
3965 spec->mixer = vaio_ar_mixer;
3966 spec->init = vaio_ar_init;
3967 spec->multiout.max_channels = 2;
3968 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3969 spec->multiout.dac_nids = vaio_dacs;
3970 spec->multiout.hp_nid = VAIO_HP_DAC;
3971 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003972 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02003973 spec->adc_nids = vaio_adcs;
3974 spec->input_mux = &vaio_mux;
3975 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003976 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003977 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003978 }
3979
Takashi Iwaidb064e52006-03-16 16:04:58 +01003980 return 0;
3981}
3982
3983
3984/*
Matt2f2f4252005-04-13 14:45:30 +02003985 * patch entries
3986 */
3987struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3988 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3989 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3990 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3991 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3992 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3993 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3994 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003995 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3996 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3997 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3998 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3999 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4000 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004001 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4002 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4003 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4004 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4005 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4006 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4007 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4008 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4009 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4010 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004011 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4012 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4013 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4014 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4015 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4016 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004017 /* The following does not take into account .id=0x83847661 when subsys =
4018 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4019 * currently not fully supported.
4020 */
4021 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4022 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4023 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004024 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4025 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4026 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4027 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4028 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4029 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4030 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4031 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004032 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4033 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004034 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004035 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4036 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4037 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4038 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4039 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4040 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4041 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4042 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4043 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004044 {} /* terminator */
4045};