blob: 34890c54bd640319f03276b4f556d9357c342262 [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
Takashi Iwai82599802007-07-31 15:56:24 +0200125 unsigned int gpio_mask, gpio_data;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100126 unsigned char aloopback_mask;
127 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200128
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100129 /* power management */
130 unsigned int num_pwrs;
131 hda_nid_t *pwr_nids;
132
Matt2f2f4252005-04-13 14:45:30 +0200133 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100134 struct hda_input_mux *mono_mux;
135 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200136 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100137 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200138
139 /* capture */
140 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200141 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200142 hda_nid_t *mux_nids;
143 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200144 hda_nid_t *dmic_nids;
145 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100146 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100147 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200148 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100149 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200150
Matt2f2f4252005-04-13 14:45:30 +0200151 /* pin widgets */
152 hda_nid_t *pin_nids;
153 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200154 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200155 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200156
157 /* codec specific stuff */
158 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100159 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200160
161 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200162 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100163 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200164 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100165 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200166
Matt Porter403d1942005-11-29 15:00:51 +0100167 /* i/o switches */
168 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200169 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200170 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200171
Mattc7d4b2f2005-06-27 14:59:41 +0200172 struct hda_pcm pcm_rec[2]; /* PCM information */
173
174 /* dynamic controls and input_mux */
175 struct auto_pin_cfg autocfg;
176 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100177 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200178 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200179 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100180 struct hda_input_mux private_mono_mux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100181
182 /* virtual master */
183 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200184};
185
186static hda_nid_t stac9200_adc_nids[1] = {
187 0x03,
188};
189
190static hda_nid_t stac9200_mux_nids[1] = {
191 0x0c,
192};
193
194static hda_nid_t stac9200_dac_nids[1] = {
195 0x02,
196};
197
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100198static hda_nid_t stac92hd73xx_pwr_nids[8] = {
199 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
200 0x0f, 0x10, 0x11
201};
202
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100203static hda_nid_t stac92hd73xx_adc_nids[2] = {
204 0x1a, 0x1b
205};
206
207#define STAC92HD73XX_NUM_DMICS 2
208static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
209 0x13, 0x14, 0
210};
211
212#define STAC92HD73_DAC_COUNT 5
213static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
214 0x15, 0x16, 0x17, 0x18, 0x19,
215};
216
217static hda_nid_t stac92hd73xx_mux_nids[4] = {
218 0x28, 0x29, 0x2a, 0x2b,
219};
220
221static hda_nid_t stac92hd73xx_dmux_nids[2] = {
222 0x20, 0x21,
223};
224
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100225static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
226 0x0a, 0x0d, 0x0f
227};
228
Matthew Ranostaye035b842007-11-06 11:53:55 +0100229static hda_nid_t stac92hd71bxx_adc_nids[2] = {
230 0x12, 0x13,
231};
232
233static hda_nid_t stac92hd71bxx_mux_nids[2] = {
234 0x1a, 0x1b
235};
236
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100237static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
238 0x1c,
239};
240
Matthew Ranostaye035b842007-11-06 11:53:55 +0100241static hda_nid_t stac92hd71bxx_dac_nids[2] = {
242 0x10, /*0x11, */
243};
244
245#define STAC92HD71BXX_NUM_DMICS 2
246static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
247 0x18, 0x19, 0
248};
249
Tobin Davis8e21c342007-01-08 11:04:17 +0100250static hda_nid_t stac925x_adc_nids[1] = {
251 0x03,
252};
253
254static hda_nid_t stac925x_mux_nids[1] = {
255 0x0f,
256};
257
258static hda_nid_t stac925x_dac_nids[1] = {
259 0x02,
260};
261
Takashi Iwaif6e98522007-10-16 14:27:04 +0200262#define STAC925X_NUM_DMICS 1
263static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
264 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200265};
266
Takashi Iwai1697055e2007-12-18 18:05:52 +0100267static hda_nid_t stac925x_dmux_nids[1] = {
268 0x14,
269};
270
Matt2f2f4252005-04-13 14:45:30 +0200271static hda_nid_t stac922x_adc_nids[2] = {
272 0x06, 0x07,
273};
274
275static hda_nid_t stac922x_mux_nids[2] = {
276 0x12, 0x13,
277};
278
Matt Porter3cc08dc2006-01-23 15:27:49 +0100279static hda_nid_t stac927x_adc_nids[3] = {
280 0x07, 0x08, 0x09
281};
282
283static hda_nid_t stac927x_mux_nids[3] = {
284 0x15, 0x16, 0x17
285};
286
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100287static hda_nid_t stac927x_dmux_nids[1] = {
288 0x1b,
289};
290
Matthew Ranostay7f168592007-10-18 17:38:17 +0200291#define STAC927X_NUM_DMICS 2
292static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
293 0x13, 0x14, 0
294};
295
Matt Porterf3302a52006-07-31 12:49:34 +0200296static hda_nid_t stac9205_adc_nids[2] = {
297 0x12, 0x13
298};
299
300static hda_nid_t stac9205_mux_nids[2] = {
301 0x19, 0x1a
302};
303
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100304static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100305 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100306};
307
Takashi Iwaif6e98522007-10-16 14:27:04 +0200308#define STAC9205_NUM_DMICS 2
309static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
310 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200311};
312
Mattc7d4b2f2005-06-27 14:59:41 +0200313static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200314 0x08, 0x09, 0x0d, 0x0e,
315 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200316};
317
Tobin Davis8e21c342007-01-08 11:04:17 +0100318static hda_nid_t stac925x_pin_nids[8] = {
319 0x07, 0x08, 0x0a, 0x0b,
320 0x0c, 0x0d, 0x10, 0x11,
321};
322
Matt2f2f4252005-04-13 14:45:30 +0200323static hda_nid_t stac922x_pin_nids[10] = {
324 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
325 0x0f, 0x10, 0x11, 0x15, 0x1b,
326};
327
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100328static hda_nid_t stac92hd73xx_pin_nids[12] = {
329 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
330 0x0f, 0x10, 0x11, 0x12, 0x13,
331 0x14, 0x22
332};
333
Matthew Ranostaye035b842007-11-06 11:53:55 +0100334static hda_nid_t stac92hd71bxx_pin_nids[10] = {
335 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
336 0x0f, 0x14, 0x18, 0x19, 0x1e,
337};
338
Matt Porter3cc08dc2006-01-23 15:27:49 +0100339static hda_nid_t stac927x_pin_nids[14] = {
340 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
341 0x0f, 0x10, 0x11, 0x12, 0x13,
342 0x14, 0x21, 0x22, 0x23,
343};
344
Matt Porterf3302a52006-07-31 12:49:34 +0200345static hda_nid_t stac9205_pin_nids[12] = {
346 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
347 0x0f, 0x14, 0x16, 0x17, 0x18,
348 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200349};
350
Matt Porter8b657272006-10-26 17:12:59 +0200351static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
352 struct snd_ctl_elem_info *uinfo)
353{
354 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
355 struct sigmatel_spec *spec = codec->spec;
356 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
357}
358
359static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
360 struct snd_ctl_elem_value *ucontrol)
361{
362 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
363 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100364 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200365
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100366 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200367 return 0;
368}
369
370static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
371 struct snd_ctl_elem_value *ucontrol)
372{
373 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
374 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100375 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200376
377 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100378 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200379}
380
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100381static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200382{
383 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
384 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200385 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200386}
387
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100388static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200389{
390 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
391 struct sigmatel_spec *spec = codec->spec;
392 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
393
394 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
395 return 0;
396}
397
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100398static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200399{
400 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
401 struct sigmatel_spec *spec = codec->spec;
402 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
403
Mattc7d4b2f2005-06-27 14:59:41 +0200404 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200405 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
406}
407
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100408static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
409 struct snd_ctl_elem_info *uinfo)
410{
411 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
412 struct sigmatel_spec *spec = codec->spec;
413 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
414}
415
416static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
417 struct snd_ctl_elem_value *ucontrol)
418{
419 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
420 struct sigmatel_spec *spec = codec->spec;
421
422 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
423 return 0;
424}
425
426static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
427 struct snd_ctl_elem_value *ucontrol)
428{
429 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
430 struct sigmatel_spec *spec = codec->spec;
431
432 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
433 spec->mono_nid, &spec->cur_mmux);
434}
435
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200436#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
437
438static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_value *ucontrol)
440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100442 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200443 struct sigmatel_spec *spec = codec->spec;
444
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100445 ucontrol->value.integer.value[0] = !!(spec->aloopback &
446 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200447 return 0;
448}
449
450static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
451 struct snd_ctl_elem_value *ucontrol)
452{
453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
454 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100455 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200456 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100457 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200458
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100459 idx_val = spec->aloopback_mask << idx;
460 if (ucontrol->value.integer.value[0])
461 val = spec->aloopback | idx_val;
462 else
463 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100464 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200465 return 0;
466
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100467 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200468
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100469 /* Only return the bits defined by the shift value of the
470 * first two bytes of the mask
471 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200472 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100473 kcontrol->private_value & 0xFFFF, 0x0);
474 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200475
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100476 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200477 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100478 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200479 } else {
480 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100481 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200482 }
483
484 snd_hda_codec_write_cache(codec, codec->afg, 0,
485 kcontrol->private_value >> 16, dac_mode);
486
487 return 1;
488}
489
Mattc7d4b2f2005-06-27 14:59:41 +0200490static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200491 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200492 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200493 {}
494};
495
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200496static struct hda_verb stac9200_eapd_init[] = {
497 /* set dac0mux for dac converter */
498 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
499 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
500 {}
501};
502
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100503static struct hda_verb stac92hd73xx_6ch_core_init[] = {
504 /* set master volume and direct control */
505 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
506 /* setup audio connections */
507 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
508 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
509 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
510 /* setup adcs to point to mixer */
511 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
512 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100513 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
514 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
515 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
516 /* setup import muxs */
517 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
518 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
519 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
520 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
521 {}
522};
523
524static struct hda_verb stac92hd73xx_8ch_core_init[] = {
525 /* set master volume and direct control */
526 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
527 /* setup audio connections */
528 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
529 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
530 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
531 /* connect hp ports to dac3 */
532 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
533 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
534 /* setup adcs to point to mixer */
535 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
536 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100537 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
538 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
539 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
540 /* setup import muxs */
541 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
542 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
543 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
544 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
545 {}
546};
547
548static struct hda_verb stac92hd73xx_10ch_core_init[] = {
549 /* set master volume and direct control */
550 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
551 /* setup audio connections */
552 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
553 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
554 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
555 /* dac3 is connected to import3 mux */
556 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
557 /* connect hp ports to dac4 */
558 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
559 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
560 /* setup adcs to point to mixer */
561 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
562 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100563 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
564 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
565 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
566 /* setup import muxs */
567 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
568 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
569 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
570 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
571 {}
572};
573
Matthew Ranostaye035b842007-11-06 11:53:55 +0100574static struct hda_verb stac92hd71bxx_core_init[] = {
575 /* set master volume and direct control */
576 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
577 /* connect headphone jack to dac1 */
578 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100579 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
580 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
581 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
582 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
583 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100584};
585
586static struct hda_verb stac92hd71bxx_analog_core_init[] = {
587 /* set master volume and direct control */
588 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
589 /* connect headphone jack to dac1 */
590 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100591 /* connect ports 0d and 0f to audio mixer */
592 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
593 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100594 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100595 /* unmute dac0 input in audio mixer */
596 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100597 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
598 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
599 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
600 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100601 {}
602};
603
Tobin Davis8e21c342007-01-08 11:04:17 +0100604static struct hda_verb stac925x_core_init[] = {
605 /* set dac0mux for dac converter */
606 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
607 {}
608};
609
Mattc7d4b2f2005-06-27 14:59:41 +0200610static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200611 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200612 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200613 {}
614};
615
Tobin Davis93ed1502006-09-01 21:03:12 +0200616static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200617 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200618 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200619 /* unmute node 0x1b */
620 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
621 /* select node 0x03 as DAC */
622 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
623 {}
624};
625
Matt Porter3cc08dc2006-01-23 15:27:49 +0100626static struct hda_verb stac927x_core_init[] = {
627 /* set master volume and direct control */
628 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
629 {}
630};
631
Matt Porterf3302a52006-07-31 12:49:34 +0200632static struct hda_verb stac9205_core_init[] = {
633 /* set master volume and direct control */
634 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
635 {}
636};
637
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100638#define STAC_MONO_MUX \
639 { \
640 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
641 .name = "Mono Mux", \
642 .count = 1, \
643 .info = stac92xx_mono_mux_enum_info, \
644 .get = stac92xx_mono_mux_enum_get, \
645 .put = stac92xx_mono_mux_enum_put, \
646 }
647
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200648#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200649 { \
650 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
651 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200652 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200653 .info = stac92xx_mux_enum_info, \
654 .get = stac92xx_mux_enum_get, \
655 .put = stac92xx_mux_enum_put, \
656 }
657
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100658#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200659 { \
660 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
661 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100662 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200663 .info = stac92xx_aloopback_info, \
664 .get = stac92xx_aloopback_get, \
665 .put = stac92xx_aloopback_put, \
666 .private_value = verb_read | (verb_write << 16), \
667 }
668
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100669static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200670 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
671 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200672 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200673 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
674 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200675 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200676 { } /* end */
677};
678
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100679static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100680 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
681
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100682 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
683 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
684
685 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
686 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
687
688 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
689 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
690
691 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
692 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
693
694 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
695 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
696
697 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
698 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
699
700 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
701 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
702 { } /* end */
703};
704
705static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100706 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
707
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100708 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
709 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
710
711 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
712 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
713
714 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
715 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
716
717 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
718 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
719
720 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
721 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
722
723 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
724 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
725
726 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
727 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
728 { } /* end */
729};
730
731static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
733
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100734 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
735 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
736
737 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
738 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
739
740 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
741 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
742
743 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
744 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
745
746 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
747 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
748
749 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
750 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
751
752 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
753 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
754 { } /* end */
755};
756
Matthew Ranostay541eee82007-12-14 12:08:04 +0100757static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100758 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100759
Matthew Ranostay9b359472007-11-07 13:03:12 +0100760 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
761 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
762 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
763
764 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
765 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
766 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
767
768 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
769 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100770 { } /* end */
771};
772
Matthew Ranostay541eee82007-12-14 12:08:04 +0100773static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100774 STAC_INPUT_SOURCE(2),
775 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
776
Matthew Ranostay541eee82007-12-14 12:08:04 +0100777 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
778 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
779 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
780
781 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
782 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
783 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
784 { } /* end */
785};
786
Tobin Davis8e21c342007-01-08 11:04:17 +0100787static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200788 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100789 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
790 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
791 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
792 { } /* end */
793};
794
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100795static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200796 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100797 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200798
799 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
800 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
801 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
802
803 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
804 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
805 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
806
807 { } /* end */
808};
809
810/* This needs to be generated dynamically based on sequence */
811static struct snd_kcontrol_new stac922x_mixer[] = {
812 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200813 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
814 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
815 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
816
817 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
818 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
819 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
820 { } /* end */
821};
822
823
824static struct snd_kcontrol_new stac927x_mixer[] = {
825 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100826 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200827
828 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
829 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
830 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
831
832 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
833 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
834 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
835
836 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
837 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
838 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200839 { } /* end */
840};
841
Takashi Iwai1697055e2007-12-18 18:05:52 +0100842static struct snd_kcontrol_new stac_dmux_mixer = {
843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
844 .name = "Digital Input Source",
845 /* count set later */
846 .info = stac92xx_dmux_enum_info,
847 .get = stac92xx_dmux_enum_get,
848 .put = stac92xx_dmux_enum_put,
849};
850
Takashi Iwai2134ea42008-01-10 16:53:55 +0100851static const char *slave_vols[] = {
852 "Front Playback Volume",
853 "Surround Playback Volume",
854 "Center Playback Volume",
855 "LFE Playback Volume",
856 "Side Playback Volume",
857 "Headphone Playback Volume",
858 "Headphone Playback Volume",
859 "Speaker Playback Volume",
860 "External Speaker Playback Volume",
861 "Speaker2 Playback Volume",
862 NULL
863};
864
865static const char *slave_sws[] = {
866 "Front Playback Switch",
867 "Surround Playback Switch",
868 "Center Playback Switch",
869 "LFE Playback Switch",
870 "Side Playback Switch",
871 "Headphone Playback Switch",
872 "Headphone Playback Switch",
873 "Speaker Playback Switch",
874 "External Speaker Playback Switch",
875 "Speaker2 Playback Switch",
876 NULL
877};
878
Matt2f2f4252005-04-13 14:45:30 +0200879static int stac92xx_build_controls(struct hda_codec *codec)
880{
881 struct sigmatel_spec *spec = codec->spec;
882 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200883 int i;
Matt2f2f4252005-04-13 14:45:30 +0200884
885 err = snd_hda_add_new_ctls(codec, spec->mixer);
886 if (err < 0)
887 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200888
889 for (i = 0; i < spec->num_mixers; i++) {
890 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
891 if (err < 0)
892 return err;
893 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100894 if (spec->num_dmuxes > 0) {
895 stac_dmux_mixer.count = spec->num_dmuxes;
896 err = snd_ctl_add(codec->bus->card,
897 snd_ctl_new1(&stac_dmux_mixer, codec));
898 if (err < 0)
899 return err;
900 }
Mattc7d4b2f2005-06-27 14:59:41 +0200901
Mattdabbed62005-06-14 10:19:34 +0200902 if (spec->multiout.dig_out_nid) {
903 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
904 if (err < 0)
905 return err;
906 }
907 if (spec->dig_in_nid) {
908 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
909 if (err < 0)
910 return err;
911 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100912
913 /* if we have no master control, let's create it */
914 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
915 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
916 HDA_OUTPUT, spec->vmaster_tlv);
917 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
918 spec->vmaster_tlv, slave_vols);
919 if (err < 0)
920 return err;
921 }
922 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
923 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
924 NULL, slave_sws);
925 if (err < 0)
926 return err;
927 }
928
Mattdabbed62005-06-14 10:19:34 +0200929 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200930}
931
Matt Porter403d1942005-11-29 15:00:51 +0100932static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200933 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200934 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
935};
936
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200937/*
938 STAC 9200 pin configs for
939 102801A8
940 102801DE
941 102801E8
942*/
943static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200944 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
945 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200946};
947
948/*
949 STAC 9200 pin configs for
950 102801C0
951 102801C1
952*/
953static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200954 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
955 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200956};
957
958/*
959 STAC 9200 pin configs for
960 102801C4 (Dell Dimension E310)
961 102801C5
962 102801C7
963 102801D9
964 102801DA
965 102801E3
966*/
967static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200968 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
969 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200970};
971
972
973/*
974 STAC 9200-32 pin configs for
975 102801B5 (Dell Inspiron 630m)
976 102801D8 (Dell Inspiron 640m)
977*/
978static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200979 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
980 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200981};
982
983/*
984 STAC 9200-32 pin configs for
985 102801C2 (Dell Latitude D620)
986 102801C8
987 102801CC (Dell Latitude D820)
988 102801D4
989 102801D6
990*/
991static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200992 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
993 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200994};
995
996/*
997 STAC 9200-32 pin configs for
998 102801CE (Dell XPS M1710)
999 102801CF (Dell Precision M90)
1000*/
1001static unsigned int dell9200_m23_pin_configs[8] = {
1002 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1003 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1004};
1005
1006/*
1007 STAC 9200-32 pin configs for
1008 102801C9
1009 102801CA
1010 102801CB (Dell Latitude 120L)
1011 102801D3
1012*/
1013static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001014 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1015 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001016};
1017
1018/*
1019 STAC 9200-32 pin configs for
1020 102801BD (Dell Inspiron E1505n)
1021 102801EE
1022 102801EF
1023*/
1024static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001025 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1026 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001027};
1028
1029/*
1030 STAC 9200-32 pin configs for
1031 102801F5 (Dell Inspiron 1501)
1032 102801F6
1033*/
1034static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001035 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1036 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001037};
1038
1039/*
1040 STAC 9200-32
1041 102801CD (Dell Inspiron E1705/9400)
1042*/
1043static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001044 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1045 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001046};
1047
1048
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001049static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1050 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001051 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1052 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1053 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1054 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1055 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1056 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1057 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1058 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1059 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1060 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001061};
1062
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001063static const char *stac9200_models[STAC_9200_MODELS] = {
1064 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001065 [STAC_9200_DELL_D21] = "dell-d21",
1066 [STAC_9200_DELL_D22] = "dell-d22",
1067 [STAC_9200_DELL_D23] = "dell-d23",
1068 [STAC_9200_DELL_M21] = "dell-m21",
1069 [STAC_9200_DELL_M22] = "dell-m22",
1070 [STAC_9200_DELL_M23] = "dell-m23",
1071 [STAC_9200_DELL_M24] = "dell-m24",
1072 [STAC_9200_DELL_M25] = "dell-m25",
1073 [STAC_9200_DELL_M26] = "dell-m26",
1074 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001075 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001076};
1077
1078static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1079 /* SigmaTel reference board */
1080 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1081 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001082 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001083 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1084 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001085 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001086 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1087 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1088 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1089 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1090 "unknown Dell", STAC_9200_DELL_D22),
1091 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1092 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001093 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001094 "Dell Latitude D620", STAC_9200_DELL_M22),
1095 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1096 "unknown Dell", STAC_9200_DELL_D23),
1097 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1098 "unknown Dell", STAC_9200_DELL_D23),
1099 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1100 "unknown Dell", STAC_9200_DELL_M22),
1101 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1102 "unknown Dell", STAC_9200_DELL_M24),
1103 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1104 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001105 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001106 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001107 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001108 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001109 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001110 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001111 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001112 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001113 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001114 "Dell Precision M90", STAC_9200_DELL_M23),
1115 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1116 "unknown Dell", STAC_9200_DELL_M22),
1117 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1118 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001119 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001120 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001121 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001122 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1123 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1124 "unknown Dell", STAC_9200_DELL_D23),
1125 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1126 "unknown Dell", STAC_9200_DELL_D23),
1127 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1128 "unknown Dell", STAC_9200_DELL_D21),
1129 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1130 "unknown Dell", STAC_9200_DELL_D23),
1131 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1132 "unknown Dell", STAC_9200_DELL_D21),
1133 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1134 "unknown Dell", STAC_9200_DELL_M25),
1135 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1136 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001137 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001138 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1139 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1140 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001141 /* Panasonic */
1142 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001143 /* Gateway machines needs EAPD to be set on resume */
1144 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1145 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1146 STAC_9200_GATEWAY),
1147 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1148 STAC_9200_GATEWAY),
Matt Porter403d1942005-11-29 15:00:51 +01001149 {} /* terminator */
1150};
1151
Tobin Davis8e21c342007-01-08 11:04:17 +01001152static unsigned int ref925x_pin_configs[8] = {
1153 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001154 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001155};
1156
1157static unsigned int stac925x_MA6_pin_configs[8] = {
1158 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1159 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1160};
1161
Tobin Davis2c11f952007-05-17 09:36:34 +02001162static unsigned int stac925x_PA6_pin_configs[8] = {
1163 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1164 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1165};
1166
Tobin Davis8e21c342007-01-08 11:04:17 +01001167static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001168 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1169 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001170};
1171
1172static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1173 [STAC_REF] = ref925x_pin_configs,
1174 [STAC_M2_2] = stac925xM2_2_pin_configs,
1175 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001176 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001177};
1178
1179static const char *stac925x_models[STAC_925x_MODELS] = {
1180 [STAC_REF] = "ref",
1181 [STAC_M2_2] = "m2-2",
1182 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001183 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001184};
1185
1186static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1187 /* SigmaTel reference board */
1188 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001189 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001190 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1191 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1192 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001193 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001194 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1195 {} /* terminator */
1196};
1197
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001198static unsigned int ref92hd73xx_pin_configs[12] = {
1199 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1200 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1201 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1202};
1203
1204static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1205 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1206};
1207
1208static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1209 [STAC_92HD73XX_REF] = "ref",
1210};
1211
1212static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1213 /* SigmaTel reference board */
1214 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1215 "DFI LanParty", STAC_92HD73XX_REF),
1216 {} /* terminator */
1217};
1218
Matthew Ranostaye035b842007-11-06 11:53:55 +01001219static unsigned int ref92hd71bxx_pin_configs[10] = {
1220 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001221 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001222 0x90a000f0, 0x01452050,
1223};
1224
1225static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1226 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1227};
1228
1229static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1230 [STAC_92HD71BXX_REF] = "ref",
1231};
1232
1233static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1234 /* SigmaTel reference board */
1235 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1236 "DFI LanParty", STAC_92HD71BXX_REF),
1237 {} /* terminator */
1238};
1239
Matt Porter403d1942005-11-29 15:00:51 +01001240static unsigned int ref922x_pin_configs[10] = {
1241 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1242 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001243 0x40000100, 0x40000100,
1244};
1245
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001246/*
1247 STAC 922X pin configs for
1248 102801A7
1249 102801AB
1250 102801A9
1251 102801D1
1252 102801D2
1253*/
1254static unsigned int dell_922x_d81_pin_configs[10] = {
1255 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1256 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1257 0x01813122, 0x400001f2,
1258};
1259
1260/*
1261 STAC 922X pin configs for
1262 102801AC
1263 102801D0
1264*/
1265static unsigned int dell_922x_d82_pin_configs[10] = {
1266 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1267 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1268 0x01813122, 0x400001f1,
1269};
1270
1271/*
1272 STAC 922X pin configs for
1273 102801BF
1274*/
1275static unsigned int dell_922x_m81_pin_configs[10] = {
1276 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1277 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1278 0x40C003f1, 0x405003f0,
1279};
1280
1281/*
1282 STAC 9221 A1 pin configs for
1283 102801D7 (Dell XPS M1210)
1284*/
1285static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001286 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1287 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001288 0x508003f3, 0x405003f4,
1289};
1290
Matt Porter403d1942005-11-29 15:00:51 +01001291static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001292 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001293 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1294 0x02a19120, 0x40000100,
1295};
1296
1297static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001298 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1299 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001300 0x02a19320, 0x40000100,
1301};
1302
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001303static unsigned int intel_mac_v1_pin_configs[10] = {
1304 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1305 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001306 0x400000fc, 0x400000fb,
1307};
1308
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001309static unsigned int intel_mac_v2_pin_configs[10] = {
1310 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1311 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001312 0x400000fc, 0x400000fb,
1313};
1314
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001315static unsigned int intel_mac_v3_pin_configs[10] = {
1316 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1317 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1318 0x400000fc, 0x400000fb,
1319};
1320
1321static unsigned int intel_mac_v4_pin_configs[10] = {
1322 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1323 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1324 0x400000fc, 0x400000fb,
1325};
1326
1327static unsigned int intel_mac_v5_pin_configs[10] = {
1328 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1329 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1330 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001331};
1332
Takashi Iwai76c08822007-06-19 12:17:42 +02001333
Takashi Iwai19039bd2006-06-28 15:52:16 +02001334static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001335 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001336 [STAC_D945GTP3] = d945gtp3_pin_configs,
1337 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001338 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1339 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1340 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1341 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1342 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001343 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001344 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1345 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1346 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1347 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1348 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1349 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001350 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1351 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1352 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1353 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001354};
1355
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001356static const char *stac922x_models[STAC_922X_MODELS] = {
1357 [STAC_D945_REF] = "ref",
1358 [STAC_D945GTP5] = "5stack",
1359 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001360 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1361 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1362 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1363 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1364 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001365 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001366 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001367 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001368 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1369 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001370 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001371 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001372 [STAC_922X_DELL_D81] = "dell-d81",
1373 [STAC_922X_DELL_D82] = "dell-d82",
1374 [STAC_922X_DELL_M81] = "dell-m81",
1375 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001376};
1377
1378static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1379 /* SigmaTel reference board */
1380 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1381 "DFI LanParty", STAC_D945_REF),
1382 /* Intel 945G based systems */
1383 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1384 "Intel D945G", STAC_D945GTP3),
1385 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1386 "Intel D945G", STAC_D945GTP3),
1387 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1388 "Intel D945G", STAC_D945GTP3),
1389 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1390 "Intel D945G", STAC_D945GTP3),
1391 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1392 "Intel D945G", STAC_D945GTP3),
1393 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1394 "Intel D945G", STAC_D945GTP3),
1395 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1396 "Intel D945G", STAC_D945GTP3),
1397 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1398 "Intel D945G", STAC_D945GTP3),
1399 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1400 "Intel D945G", STAC_D945GTP3),
1401 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1402 "Intel D945G", STAC_D945GTP3),
1403 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1404 "Intel D945G", STAC_D945GTP3),
1405 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1406 "Intel D945G", STAC_D945GTP3),
1407 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1408 "Intel D945G", STAC_D945GTP3),
1409 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1410 "Intel D945G", STAC_D945GTP3),
1411 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1412 "Intel D945G", STAC_D945GTP3),
1413 /* Intel D945G 5-stack systems */
1414 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1415 "Intel D945G", STAC_D945GTP5),
1416 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1417 "Intel D945G", STAC_D945GTP5),
1418 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1419 "Intel D945G", STAC_D945GTP5),
1420 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1421 "Intel D945G", STAC_D945GTP5),
1422 /* Intel 945P based systems */
1423 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1424 "Intel D945P", STAC_D945GTP3),
1425 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1426 "Intel D945P", STAC_D945GTP3),
1427 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1428 "Intel D945P", STAC_D945GTP3),
1429 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1430 "Intel D945P", STAC_D945GTP3),
1431 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1432 "Intel D945P", STAC_D945GTP3),
1433 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1434 "Intel D945P", STAC_D945GTP5),
1435 /* other systems */
1436 /* Apple Mac Mini (early 2006) */
1437 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001438 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001439 /* Dell systems */
1440 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1441 "unknown Dell", STAC_922X_DELL_D81),
1442 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1443 "unknown Dell", STAC_922X_DELL_D81),
1444 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1445 "unknown Dell", STAC_922X_DELL_D81),
1446 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1447 "unknown Dell", STAC_922X_DELL_D82),
1448 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1449 "unknown Dell", STAC_922X_DELL_M81),
1450 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1451 "unknown Dell", STAC_922X_DELL_D82),
1452 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1453 "unknown Dell", STAC_922X_DELL_D81),
1454 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1455 "unknown Dell", STAC_922X_DELL_D81),
1456 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1457 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001458 {} /* terminator */
1459};
1460
Matt Porter3cc08dc2006-01-23 15:27:49 +01001461static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001462 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1463 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1464 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1465 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001466};
1467
Tobin Davis93ed1502006-09-01 21:03:12 +02001468static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001469 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1470 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1471 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1472 0x40000100, 0x40000100
1473};
1474
Tobin Davis93ed1502006-09-01 21:03:12 +02001475static unsigned int d965_5st_pin_configs[14] = {
1476 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1477 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1478 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1479 0x40000100, 0x40000100
1480};
1481
Tobin Davis4ff076e2007-08-07 11:48:12 +02001482static unsigned int dell_3st_pin_configs[14] = {
1483 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1484 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001485 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001486 0x40c003fc, 0x40000100
1487};
1488
Tobin Davis93ed1502006-09-01 21:03:12 +02001489static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001490 [STAC_D965_REF] = ref927x_pin_configs,
1491 [STAC_D965_3ST] = d965_3st_pin_configs,
1492 [STAC_D965_5ST] = d965_5st_pin_configs,
1493 [STAC_DELL_3ST] = dell_3st_pin_configs,
1494 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001495};
1496
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001497static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001498 [STAC_D965_REF] = "ref",
1499 [STAC_D965_3ST] = "3stack",
1500 [STAC_D965_5ST] = "5stack",
1501 [STAC_DELL_3ST] = "dell-3stack",
1502 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001503};
1504
1505static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1506 /* SigmaTel reference board */
1507 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1508 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001509 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001510 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1511 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001512 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1514 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1516 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1518 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1520 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1521 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1522 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1524 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1526 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001529 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001530 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001531 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001532 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001534 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001535 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001537 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001543 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001553 {} /* terminator */
1554};
1555
Matt Porterf3302a52006-07-31 12:49:34 +02001556static unsigned int ref9205_pin_configs[12] = {
1557 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001558 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001559 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001560};
1561
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001562/*
1563 STAC 9205 pin configs for
1564 102801F1
1565 102801F2
1566 102801FC
1567 102801FD
1568 10280204
1569 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001570 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001571*/
1572static unsigned int dell_9205_m42_pin_configs[12] = {
1573 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1574 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1575 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1576};
1577
1578/*
1579 STAC 9205 pin configs for
1580 102801F9
1581 102801FA
1582 102801FE
1583 102801FF (Dell Precision M4300)
1584 10280206
1585 10280200
1586 10280201
1587*/
1588static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001589 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1590 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1591 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1592};
1593
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001594static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001595 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1596 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1597 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1598};
1599
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001600static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001601 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001602 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1603 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1604 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001605};
1606
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001607static const char *stac9205_models[STAC_9205_MODELS] = {
1608 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001609 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001610 [STAC_9205_DELL_M43] = "dell-m43",
1611 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001612};
1613
1614static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1615 /* SigmaTel reference board */
1616 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1617 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001618 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1619 "unknown Dell", STAC_9205_DELL_M42),
1620 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1621 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001622 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001623 "Dell Precision", STAC_9205_DELL_M43),
1624 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1625 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001626 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1627 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001628 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1629 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001630 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1631 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001632 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1633 "unknown Dell", STAC_9205_DELL_M42),
1634 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1635 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001636 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1637 "Dell Precision", STAC_9205_DELL_M43),
1638 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001639 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001640 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1641 "Dell Precision", STAC_9205_DELL_M43),
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1643 "Dell Inspiron", STAC_9205_DELL_M44),
1644 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1645 "Dell Inspiron", STAC_9205_DELL_M44),
1646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1647 "Dell Inspiron", STAC_9205_DELL_M44),
1648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1649 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001650 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1651 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001652 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1653 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001654 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1655 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001656 {} /* terminator */
1657};
1658
Richard Fish11b44bb2006-08-23 18:31:34 +02001659static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1660{
1661 int i;
1662 struct sigmatel_spec *spec = codec->spec;
1663
1664 if (! spec->bios_pin_configs) {
1665 spec->bios_pin_configs = kcalloc(spec->num_pins,
1666 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1667 if (! spec->bios_pin_configs)
1668 return -ENOMEM;
1669 }
1670
1671 for (i = 0; i < spec->num_pins; i++) {
1672 hda_nid_t nid = spec->pin_nids[i];
1673 unsigned int pin_cfg;
1674
1675 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1676 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1677 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1678 nid, pin_cfg);
1679 spec->bios_pin_configs[i] = pin_cfg;
1680 }
1681
1682 return 0;
1683}
1684
Matthew Ranostay87d48362007-07-17 11:52:24 +02001685static void stac92xx_set_config_reg(struct hda_codec *codec,
1686 hda_nid_t pin_nid, unsigned int pin_config)
1687{
1688 int i;
1689 snd_hda_codec_write(codec, pin_nid, 0,
1690 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1691 pin_config & 0x000000ff);
1692 snd_hda_codec_write(codec, pin_nid, 0,
1693 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1694 (pin_config & 0x0000ff00) >> 8);
1695 snd_hda_codec_write(codec, pin_nid, 0,
1696 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1697 (pin_config & 0x00ff0000) >> 16);
1698 snd_hda_codec_write(codec, pin_nid, 0,
1699 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1700 pin_config >> 24);
1701 i = snd_hda_codec_read(codec, pin_nid, 0,
1702 AC_VERB_GET_CONFIG_DEFAULT,
1703 0x00);
1704 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1705 pin_nid, i);
1706}
1707
Matt2f2f4252005-04-13 14:45:30 +02001708static void stac92xx_set_config_regs(struct hda_codec *codec)
1709{
1710 int i;
1711 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001712
Matthew Ranostay87d48362007-07-17 11:52:24 +02001713 if (!spec->pin_configs)
1714 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001715
Matthew Ranostay87d48362007-07-17 11:52:24 +02001716 for (i = 0; i < spec->num_pins; i++)
1717 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1718 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001719}
Matt2f2f4252005-04-13 14:45:30 +02001720
Matt2f2f4252005-04-13 14:45:30 +02001721/*
1722 * Analog playback callbacks
1723 */
1724static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1725 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001726 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001727{
1728 struct sigmatel_spec *spec = codec->spec;
1729 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1730}
1731
1732static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1733 struct hda_codec *codec,
1734 unsigned int stream_tag,
1735 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001736 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001737{
1738 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001739 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001740}
1741
1742static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1743 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001744 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001745{
1746 struct sigmatel_spec *spec = codec->spec;
1747 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1748}
1749
1750/*
Mattdabbed62005-06-14 10:19:34 +02001751 * Digital playback callbacks
1752 */
1753static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1754 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001755 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001756{
1757 struct sigmatel_spec *spec = codec->spec;
1758 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1759}
1760
1761static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1762 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001763 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001764{
1765 struct sigmatel_spec *spec = codec->spec;
1766 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1767}
1768
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001769static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1770 struct hda_codec *codec,
1771 unsigned int stream_tag,
1772 unsigned int format,
1773 struct snd_pcm_substream *substream)
1774{
1775 struct sigmatel_spec *spec = codec->spec;
1776 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1777 stream_tag, format, substream);
1778}
1779
Mattdabbed62005-06-14 10:19:34 +02001780
1781/*
Matt2f2f4252005-04-13 14:45:30 +02001782 * Analog capture callbacks
1783 */
1784static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1785 struct hda_codec *codec,
1786 unsigned int stream_tag,
1787 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001788 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001789{
1790 struct sigmatel_spec *spec = codec->spec;
1791
1792 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1793 stream_tag, 0, format);
1794 return 0;
1795}
1796
1797static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1798 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001799 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001800{
1801 struct sigmatel_spec *spec = codec->spec;
1802
1803 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1804 return 0;
1805}
1806
Mattdabbed62005-06-14 10:19:34 +02001807static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1808 .substreams = 1,
1809 .channels_min = 2,
1810 .channels_max = 2,
1811 /* NID is set in stac92xx_build_pcms */
1812 .ops = {
1813 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001814 .close = stac92xx_dig_playback_pcm_close,
1815 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001816 },
1817};
1818
1819static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1820 .substreams = 1,
1821 .channels_min = 2,
1822 .channels_max = 2,
1823 /* NID is set in stac92xx_build_pcms */
1824};
1825
Matt2f2f4252005-04-13 14:45:30 +02001826static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1827 .substreams = 1,
1828 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001829 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001830 .nid = 0x02, /* NID to query formats and rates */
1831 .ops = {
1832 .open = stac92xx_playback_pcm_open,
1833 .prepare = stac92xx_playback_pcm_prepare,
1834 .cleanup = stac92xx_playback_pcm_cleanup
1835 },
1836};
1837
Matt Porter3cc08dc2006-01-23 15:27:49 +01001838static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1839 .substreams = 1,
1840 .channels_min = 2,
1841 .channels_max = 2,
1842 .nid = 0x06, /* NID to query formats and rates */
1843 .ops = {
1844 .open = stac92xx_playback_pcm_open,
1845 .prepare = stac92xx_playback_pcm_prepare,
1846 .cleanup = stac92xx_playback_pcm_cleanup
1847 },
1848};
1849
Matt2f2f4252005-04-13 14:45:30 +02001850static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001851 .channels_min = 2,
1852 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001853 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001854 .ops = {
1855 .prepare = stac92xx_capture_pcm_prepare,
1856 .cleanup = stac92xx_capture_pcm_cleanup
1857 },
1858};
1859
1860static int stac92xx_build_pcms(struct hda_codec *codec)
1861{
1862 struct sigmatel_spec *spec = codec->spec;
1863 struct hda_pcm *info = spec->pcm_rec;
1864
1865 codec->num_pcms = 1;
1866 codec->pcm_info = info;
1867
Mattc7d4b2f2005-06-27 14:59:41 +02001868 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001869 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001870 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001871 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001872 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001873
1874 if (spec->alt_switch) {
1875 codec->num_pcms++;
1876 info++;
1877 info->name = "STAC92xx Analog Alt";
1878 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1879 }
Matt2f2f4252005-04-13 14:45:30 +02001880
Mattdabbed62005-06-14 10:19:34 +02001881 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1882 codec->num_pcms++;
1883 info++;
1884 info->name = "STAC92xx Digital";
1885 if (spec->multiout.dig_out_nid) {
1886 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1887 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1888 }
1889 if (spec->dig_in_nid) {
1890 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1891 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1892 }
1893 }
1894
Matt2f2f4252005-04-13 14:45:30 +02001895 return 0;
1896}
1897
Takashi Iwaic960a032006-03-23 17:06:28 +01001898static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1899{
1900 unsigned int pincap = snd_hda_param_read(codec, nid,
1901 AC_PAR_PIN_CAP);
1902 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1903 if (pincap & AC_PINCAP_VREF_100)
1904 return AC_PINCTL_VREF_100;
1905 if (pincap & AC_PINCAP_VREF_80)
1906 return AC_PINCTL_VREF_80;
1907 if (pincap & AC_PINCAP_VREF_50)
1908 return AC_PINCTL_VREF_50;
1909 if (pincap & AC_PINCAP_VREF_GRD)
1910 return AC_PINCTL_VREF_GRD;
1911 return 0;
1912}
1913
Matt Porter403d1942005-11-29 15:00:51 +01001914static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1915
1916{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001917 snd_hda_codec_write_cache(codec, nid, 0,
1918 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001919}
1920
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001921#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001922
1923static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1924{
1925 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1926 struct sigmatel_spec *spec = codec->spec;
1927 int io_idx = kcontrol-> private_value & 0xff;
1928
1929 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1930 return 0;
1931}
1932
1933static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1934{
1935 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1936 struct sigmatel_spec *spec = codec->spec;
1937 hda_nid_t nid = kcontrol->private_value >> 8;
1938 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001939 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001940
1941 spec->io_switch[io_idx] = val;
1942
1943 if (val)
1944 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001945 else {
1946 unsigned int pinctl = AC_PINCTL_IN_EN;
1947 if (io_idx) /* set VREF for mic */
1948 pinctl |= stac92xx_get_vref(codec, nid);
1949 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1950 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001951
1952 /* check the auto-mute again: we need to mute/unmute the speaker
1953 * appropriately according to the pin direction
1954 */
1955 if (spec->hp_detect)
1956 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1957
Matt Porter403d1942005-11-29 15:00:51 +01001958 return 1;
1959}
1960
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001961#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1962
1963static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1964 struct snd_ctl_elem_value *ucontrol)
1965{
1966 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1967 struct sigmatel_spec *spec = codec->spec;
1968
1969 ucontrol->value.integer.value[0] = spec->clfe_swap;
1970 return 0;
1971}
1972
1973static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1974 struct snd_ctl_elem_value *ucontrol)
1975{
1976 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1977 struct sigmatel_spec *spec = codec->spec;
1978 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001979 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001980
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001981 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001982 return 0;
1983
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001984 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001985
1986 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1987 spec->clfe_swap ? 0x4 : 0x0);
1988
1989 return 1;
1990}
1991
Matt Porter403d1942005-11-29 15:00:51 +01001992#define STAC_CODEC_IO_SWITCH(xname, xpval) \
1993 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1994 .name = xname, \
1995 .index = 0, \
1996 .info = stac92xx_io_switch_info, \
1997 .get = stac92xx_io_switch_get, \
1998 .put = stac92xx_io_switch_put, \
1999 .private_value = xpval, \
2000 }
2001
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002002#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2003 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2004 .name = xname, \
2005 .index = 0, \
2006 .info = stac92xx_clfe_switch_info, \
2007 .get = stac92xx_clfe_switch_get, \
2008 .put = stac92xx_clfe_switch_put, \
2009 .private_value = xpval, \
2010 }
Matt Porter403d1942005-11-29 15:00:51 +01002011
Mattc7d4b2f2005-06-27 14:59:41 +02002012enum {
2013 STAC_CTL_WIDGET_VOL,
2014 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002015 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002016 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002017 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002018};
2019
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002020static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002021 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2022 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002023 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002024 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002025 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002026};
2027
2028/* add dynamic controls */
2029static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2030{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002031 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002032
2033 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2034 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2035
2036 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2037 if (! knew)
2038 return -ENOMEM;
2039 if (spec->kctl_alloc) {
2040 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2041 kfree(spec->kctl_alloc);
2042 }
2043 spec->kctl_alloc = knew;
2044 spec->num_kctl_alloc = num;
2045 }
2046
2047 knew = &spec->kctl_alloc[spec->num_kctl_used];
2048 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002049 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002050 if (! knew->name)
2051 return -ENOMEM;
2052 knew->private_value = val;
2053 spec->num_kctl_used++;
2054 return 0;
2055}
2056
Matt Porter403d1942005-11-29 15:00:51 +01002057/* flag inputs as additional dynamic lineouts */
2058static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2059{
2060 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002061 unsigned int wcaps, wtype;
2062 int i, num_dacs = 0;
2063
2064 /* use the wcaps cache to count all DACs available for line-outs */
2065 for (i = 0; i < codec->num_nodes; i++) {
2066 wcaps = codec->wcaps[i];
2067 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002068
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002069 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2070 num_dacs++;
2071 }
Matt Porter403d1942005-11-29 15:00:51 +01002072
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002073 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2074
Matt Porter403d1942005-11-29 15:00:51 +01002075 switch (cfg->line_outs) {
2076 case 3:
2077 /* add line-in as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002078 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002079 cfg->line_out_pins[cfg->line_outs] =
2080 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002081 spec->line_switch = 1;
2082 cfg->line_outs++;
2083 }
2084 break;
2085 case 2:
2086 /* add line-in as clfe and mic as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002087 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002088 cfg->line_out_pins[cfg->line_outs] =
2089 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002090 spec->line_switch = 1;
2091 cfg->line_outs++;
2092 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002093 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002094 cfg->line_out_pins[cfg->line_outs] =
2095 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002096 spec->mic_switch = 1;
2097 cfg->line_outs++;
2098 }
2099 break;
2100 case 1:
2101 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002102 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002103 cfg->line_out_pins[cfg->line_outs] =
2104 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002105 spec->line_switch = 1;
2106 cfg->line_outs++;
2107 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002108 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002109 cfg->line_out_pins[cfg->line_outs] =
2110 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002111 spec->mic_switch = 1;
2112 cfg->line_outs++;
2113 }
2114 break;
2115 }
2116
2117 return 0;
2118}
2119
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002120
2121static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2122{
2123 int i;
2124
2125 for (i = 0; i < spec->multiout.num_dacs; i++) {
2126 if (spec->multiout.dac_nids[i] == nid)
2127 return 1;
2128 }
2129
2130 return 0;
2131}
2132
Matt Porter3cc08dc2006-01-23 15:27:49 +01002133/*
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002134 * Fill in the dac_nids table from the parsed pin configuration
2135 * This function only works when every pin in line_out_pins[]
2136 * contains atleast one DAC in its connection list. Some 92xx
2137 * codecs are not connected directly to a DAC, such as the 9200
2138 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002139 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002140static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002141 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002142{
2143 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002144 int i, j, conn_len = 0;
2145 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2146 unsigned int wcaps, wtype;
2147
Mattc7d4b2f2005-06-27 14:59:41 +02002148 for (i = 0; i < cfg->line_outs; i++) {
2149 nid = cfg->line_out_pins[i];
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002150 conn_len = snd_hda_get_connections(codec, nid, conn,
2151 HDA_MAX_CONNECTIONS);
2152 for (j = 0; j < conn_len; j++) {
2153 wcaps = snd_hda_param_read(codec, conn[j],
2154 AC_PAR_AUDIO_WIDGET_CAP);
2155 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002156 if (wtype != AC_WID_AUD_OUT ||
2157 (wcaps & AC_WCAP_DIGITAL))
2158 continue;
2159 /* conn[j] is a DAC routed to this line-out */
2160 if (!is_in_dac_nids(spec, conn[j]))
2161 break;
2162 }
2163
2164 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002165 if (spec->multiout.num_dacs > 0) {
2166 /* we have already working output pins,
2167 * so let's drop the broken ones again
2168 */
2169 cfg->line_outs = spec->multiout.num_dacs;
2170 break;
2171 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002172 /* error out, no available DAC found */
2173 snd_printk(KERN_ERR
2174 "%s: No available DAC for pin 0x%x\n",
2175 __func__, nid);
2176 return -ENODEV;
2177 }
2178
2179 spec->multiout.dac_nids[i] = conn[j];
2180 spec->multiout.num_dacs++;
2181 if (conn_len > 1) {
2182 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002183 snd_hda_codec_write_cache(codec, nid, 0,
2184 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002185
2186 }
Mattc7d4b2f2005-06-27 14:59:41 +02002187 }
2188
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002189 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2190 spec->multiout.num_dacs,
2191 spec->multiout.dac_nids[0],
2192 spec->multiout.dac_nids[1],
2193 spec->multiout.dac_nids[2],
2194 spec->multiout.dac_nids[3],
2195 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002196 return 0;
2197}
2198
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002199/* create volume control/switch for the given prefx type */
2200static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2201{
2202 char name[32];
2203 int err;
2204
2205 sprintf(name, "%s Playback Volume", pfx);
2206 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2207 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2208 if (err < 0)
2209 return err;
2210 sprintf(name, "%s Playback Switch", pfx);
2211 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2212 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2213 if (err < 0)
2214 return err;
2215 return 0;
2216}
2217
Mattc7d4b2f2005-06-27 14:59:41 +02002218/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002219static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002220 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002221{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002222 static const char *chname[4] = {
2223 "Front", "Surround", NULL /*CLFE*/, "Side"
2224 };
Mattc7d4b2f2005-06-27 14:59:41 +02002225 hda_nid_t nid;
2226 int i, err;
2227
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002228 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002229 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002230
2231
Mattc7d4b2f2005-06-27 14:59:41 +02002232 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002233 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002234 continue;
2235
2236 nid = spec->multiout.dac_nids[i];
2237
2238 if (i == 2) {
2239 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002240 err = create_controls(spec, "Center", nid, 1);
2241 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002242 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002243 err = create_controls(spec, "LFE", nid, 2);
2244 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002245 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002246
2247 wid_caps = get_wcaps(codec, nid);
2248
2249 if (wid_caps & AC_WCAP_LR_SWAP) {
2250 err = stac92xx_add_control(spec,
2251 STAC_CTL_WIDGET_CLFE_SWITCH,
2252 "Swap Center/LFE Playback Switch", nid);
2253
2254 if (err < 0)
2255 return err;
2256 }
2257
Mattc7d4b2f2005-06-27 14:59:41 +02002258 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002259 err = create_controls(spec, chname[i], nid, 3);
2260 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002261 return err;
2262 }
2263 }
2264
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002265 if (spec->line_switch) {
2266 nid = cfg->input_pins[AUTO_PIN_LINE];
2267 pincap = snd_hda_param_read(codec, nid,
2268 AC_PAR_PIN_CAP);
2269 if (pincap & AC_PINCAP_OUT) {
2270 err = stac92xx_add_control(spec,
2271 STAC_CTL_WIDGET_IO_SWITCH,
2272 "Line In as Output Switch", nid << 8);
2273 if (err < 0)
2274 return err;
2275 }
2276 }
Matt Porter403d1942005-11-29 15:00:51 +01002277
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002278 if (spec->mic_switch) {
2279 nid = cfg->input_pins[AUTO_PIN_MIC];
2280 pincap = snd_hda_param_read(codec, nid,
2281 AC_PAR_PIN_CAP);
2282 if (pincap & AC_PINCAP_OUT) {
2283 err = stac92xx_add_control(spec,
2284 STAC_CTL_WIDGET_IO_SWITCH,
2285 "Mic as Output Switch", (nid << 8) | 1);
2286 if (err < 0)
2287 return err;
2288 }
2289 }
Matt Porter403d1942005-11-29 15:00:51 +01002290
Mattc7d4b2f2005-06-27 14:59:41 +02002291 return 0;
2292}
2293
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002294static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2295{
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002296 if (is_in_dac_nids(spec, nid))
2297 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002298 if (spec->multiout.hp_nid == nid)
2299 return 1;
2300 return 0;
2301}
2302
2303static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2304{
2305 if (!spec->multiout.hp_nid)
2306 spec->multiout.hp_nid = nid;
2307 else if (spec->multiout.num_dacs > 4) {
2308 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2309 return 1;
2310 } else {
2311 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2312 spec->multiout.num_dacs++;
2313 }
2314 return 0;
2315}
2316
2317/* add playback controls for Speaker and HP outputs */
2318static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2319 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002320{
2321 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002322 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002323 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002324
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002325 old_num_dacs = spec->multiout.num_dacs;
2326 for (i = 0; i < cfg->hp_outs; i++) {
2327 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2328 if (wid_caps & AC_WCAP_UNSOL_CAP)
2329 spec->hp_detect = 1;
2330 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2331 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2332 if (check_in_dac_nids(spec, nid))
2333 nid = 0;
2334 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002335 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002336 add_spec_dacs(spec, nid);
2337 }
2338 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002339 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002340 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2341 if (check_in_dac_nids(spec, nid))
2342 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002343 if (! nid)
2344 continue;
2345 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002346 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002347 for (i = 0; i < cfg->line_outs; i++) {
2348 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2349 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2350 if (check_in_dac_nids(spec, nid))
2351 nid = 0;
2352 if (! nid)
2353 continue;
2354 add_spec_dacs(spec, nid);
2355 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002356 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2357 static const char *pfxs[] = {
2358 "Speaker", "External Speaker", "Speaker2",
2359 };
2360 err = create_controls(spec, pfxs[i - old_num_dacs],
2361 spec->multiout.dac_nids[i], 3);
2362 if (err < 0)
2363 return err;
2364 }
2365 if (spec->multiout.hp_nid) {
2366 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002367 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002368 pfx = "Master";
2369 else
2370 pfx = "Headphone";
2371 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2372 if (err < 0)
2373 return err;
2374 }
Mattc7d4b2f2005-06-27 14:59:41 +02002375
2376 return 0;
2377}
2378
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002379/* labels for mono mux outputs */
2380static const char *stac92xx_mono_labels[3] = {
2381 "DAC0", "DAC1", "Mixer"
2382};
2383
2384/* create mono mux for mono out on capable codecs */
2385static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2386{
2387 struct sigmatel_spec *spec = codec->spec;
2388 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2389 int i, num_cons;
2390 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2391
2392 num_cons = snd_hda_get_connections(codec,
2393 spec->mono_nid,
2394 con_lst,
2395 HDA_MAX_NUM_INPUTS);
2396 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2397 return -EINVAL;
2398
2399 for (i = 0; i < num_cons; i++) {
2400 mono_mux->items[mono_mux->num_items].label =
2401 stac92xx_mono_labels[i];
2402 mono_mux->items[mono_mux->num_items].index = i;
2403 mono_mux->num_items++;
2404 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002405
2406 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2407 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002408}
2409
Matt Porter8b657272006-10-26 17:12:59 +02002410/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002411static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002412 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2413 "Digital Mic 3", "Digital Mic 4"
2414};
2415
2416/* create playback/capture controls for input pins on dmic capable codecs */
2417static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2418 const struct auto_pin_cfg *cfg)
2419{
2420 struct sigmatel_spec *spec = codec->spec;
2421 struct hda_input_mux *dimux = &spec->private_dimux;
2422 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002423 int err, i, j;
2424 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002425
2426 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2427 dimux->items[dimux->num_items].index = 0;
2428 dimux->num_items++;
2429
2430 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002431 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002432 int index;
2433 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002434 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002435 unsigned int def_conf;
2436
2437 def_conf = snd_hda_codec_read(codec,
2438 spec->dmic_nids[i],
2439 0,
2440 AC_VERB_GET_CONFIG_DEFAULT,
2441 0);
2442 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2443 continue;
2444
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002445 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002446 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002447 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002448 con_lst,
2449 HDA_MAX_NUM_INPUTS);
2450 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002451 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002452 index = j;
2453 goto found;
2454 }
2455 continue;
2456found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002457 wcaps = get_wcaps(codec, nid);
2458
2459 if (wcaps & AC_WCAP_OUT_AMP) {
2460 sprintf(name, "%s Capture Volume",
2461 stac92xx_dmic_labels[dimux->num_items]);
2462
2463 err = stac92xx_add_control(spec,
2464 STAC_CTL_WIDGET_VOL,
2465 name,
2466 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2467 if (err < 0)
2468 return err;
2469 }
2470
Matt Porter8b657272006-10-26 17:12:59 +02002471 dimux->items[dimux->num_items].label =
2472 stac92xx_dmic_labels[dimux->num_items];
2473 dimux->items[dimux->num_items].index = index;
2474 dimux->num_items++;
2475 }
2476
2477 return 0;
2478}
2479
Mattc7d4b2f2005-06-27 14:59:41 +02002480/* create playback/capture controls for input pins */
2481static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2482{
2483 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002484 struct hda_input_mux *imux = &spec->private_imux;
2485 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2486 int i, j, k;
2487
2488 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002489 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002490
Takashi Iwai314634b2006-09-21 11:56:18 +02002491 if (!cfg->input_pins[i])
2492 continue;
2493 index = -1;
2494 for (j = 0; j < spec->num_muxes; j++) {
2495 int num_cons;
2496 num_cons = snd_hda_get_connections(codec,
2497 spec->mux_nids[j],
2498 con_lst,
2499 HDA_MAX_NUM_INPUTS);
2500 for (k = 0; k < num_cons; k++)
2501 if (con_lst[k] == cfg->input_pins[i]) {
2502 index = k;
2503 goto found;
2504 }
Mattc7d4b2f2005-06-27 14:59:41 +02002505 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002506 continue;
2507 found:
2508 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2509 imux->items[imux->num_items].index = index;
2510 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002511 }
2512
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002513 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002514 /*
2515 * Set the current input for the muxes.
2516 * The STAC9221 has two input muxes with identical source
2517 * NID lists. Hopefully this won't get confused.
2518 */
2519 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002520 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2521 AC_VERB_SET_CONNECT_SEL,
2522 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002523 }
2524 }
2525
Mattc7d4b2f2005-06-27 14:59:41 +02002526 return 0;
2527}
2528
Mattc7d4b2f2005-06-27 14:59:41 +02002529static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2530{
2531 struct sigmatel_spec *spec = codec->spec;
2532 int i;
2533
2534 for (i = 0; i < spec->autocfg.line_outs; i++) {
2535 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2536 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2537 }
2538}
2539
2540static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2541{
2542 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002543 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002544
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002545 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2546 hda_nid_t pin;
2547 pin = spec->autocfg.hp_pins[i];
2548 if (pin) /* connect to front */
2549 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2550 }
2551 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2552 hda_nid_t pin;
2553 pin = spec->autocfg.speaker_pins[i];
2554 if (pin) /* connect to front */
2555 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2556 }
Mattc7d4b2f2005-06-27 14:59:41 +02002557}
2558
Matt Porter3cc08dc2006-01-23 15:27:49 +01002559static 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 +02002560{
2561 struct sigmatel_spec *spec = codec->spec;
2562 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002563 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002564
Matt Porter8b657272006-10-26 17:12:59 +02002565 if ((err = snd_hda_parse_pin_def_config(codec,
2566 &spec->autocfg,
2567 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002568 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002569 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002570 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002571
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002572 /* If we have no real line-out pin and multiple hp-outs, HPs should
2573 * be set up as multi-channel outputs.
2574 */
2575 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2576 spec->autocfg.hp_outs > 1) {
2577 /* Copy hp_outs to line_outs, backup line_outs in
2578 * speaker_outs so that the following routines can handle
2579 * HP pins as primary outputs.
2580 */
2581 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2582 sizeof(spec->autocfg.line_out_pins));
2583 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2584 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2585 sizeof(spec->autocfg.hp_pins));
2586 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2587 hp_speaker_swap = 1;
2588 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002589 if (spec->autocfg.mono_out_pin) {
2590 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2591 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2592 u32 caps = query_amp_caps(codec,
2593 spec->autocfg.mono_out_pin, dir);
2594 hda_nid_t conn_list[1];
2595
2596 /* get the mixer node and then the mono mux if it exists */
2597 if (snd_hda_get_connections(codec,
2598 spec->autocfg.mono_out_pin, conn_list, 1) &&
2599 snd_hda_get_connections(codec, conn_list[0],
2600 conn_list, 1)) {
2601
2602 int wcaps = get_wcaps(codec, conn_list[0]);
2603 int wid_type = (wcaps & AC_WCAP_TYPE)
2604 >> AC_WCAP_TYPE_SHIFT;
2605 /* LR swap check, some stac925x have a mux that
2606 * changes the DACs output path instead of the
2607 * mono-mux path.
2608 */
2609 if (wid_type == AC_WID_AUD_SEL &&
2610 !(wcaps & AC_WCAP_LR_SWAP))
2611 spec->mono_nid = conn_list[0];
2612 }
2613 /* all mono outs have a least a mute/unmute switch */
2614 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2615 "Mono Playback Switch",
2616 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2617 1, 0, dir));
2618 if (err < 0)
2619 return err;
2620 /* check to see if there is volume support for the amp */
2621 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2622 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2623 "Mono Playback Volume",
2624 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2625 1, 0, dir));
2626 if (err < 0)
2627 return err;
2628 }
2629
2630 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2631 AC_PINCTL_OUT_EN);
2632 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002633
Matt Porter403d1942005-11-29 15:00:51 +01002634 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2635 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002636 if (spec->multiout.num_dacs == 0)
2637 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2638 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002639
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002640 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2641
2642 if (err < 0)
2643 return err;
2644
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002645 if (hp_speaker_swap == 1) {
2646 /* Restore the hp_outs and line_outs */
2647 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2648 sizeof(spec->autocfg.line_out_pins));
2649 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2650 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2651 sizeof(spec->autocfg.speaker_pins));
2652 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2653 memset(spec->autocfg.speaker_pins, 0,
2654 sizeof(spec->autocfg.speaker_pins));
2655 spec->autocfg.speaker_outs = 0;
2656 }
2657
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002658 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2659
2660 if (err < 0)
2661 return err;
2662
2663 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2664
2665 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002666 return err;
2667
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002668 if (spec->mono_nid > 0) {
2669 err = stac92xx_auto_create_mono_output_ctls(codec);
2670 if (err < 0)
2671 return err;
2672 }
2673
Matt Porter8b657272006-10-26 17:12:59 +02002674 if (spec->num_dmics > 0)
2675 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2676 &spec->autocfg)) < 0)
2677 return err;
2678
Mattc7d4b2f2005-06-27 14:59:41 +02002679 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002680 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002681 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002682
Takashi Iwai82bc9552006-03-21 11:24:42 +01002683 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002684 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002685 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002686 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002687
2688 if (spec->kctl_alloc)
2689 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2690
2691 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002692 if (!spec->dinput_mux)
2693 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002694 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002695
2696 return 1;
2697}
2698
Takashi Iwai82bc9552006-03-21 11:24:42 +01002699/* add playback controls for HP output */
2700static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2701 struct auto_pin_cfg *cfg)
2702{
2703 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002704 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002705 unsigned int wid_caps;
2706
2707 if (! pin)
2708 return 0;
2709
2710 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002711 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002712 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002713
2714 return 0;
2715}
2716
Richard Fish160ea0d2006-09-06 13:58:25 +02002717/* add playback controls for LFE output */
2718static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2719 struct auto_pin_cfg *cfg)
2720{
2721 struct sigmatel_spec *spec = codec->spec;
2722 int err;
2723 hda_nid_t lfe_pin = 0x0;
2724 int i;
2725
2726 /*
2727 * search speaker outs and line outs for a mono speaker pin
2728 * with an amp. If one is found, add LFE controls
2729 * for it.
2730 */
2731 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2732 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2733 unsigned long wcaps = get_wcaps(codec, pin);
2734 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2735 if (wcaps == AC_WCAP_OUT_AMP)
2736 /* found a mono speaker with an amp, must be lfe */
2737 lfe_pin = pin;
2738 }
2739
2740 /* if speaker_outs is 0, then speakers may be in line_outs */
2741 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2742 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2743 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2744 unsigned long cfg;
2745 cfg = snd_hda_codec_read(codec, pin, 0,
2746 AC_VERB_GET_CONFIG_DEFAULT,
2747 0x00);
2748 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2749 unsigned long wcaps = get_wcaps(codec, pin);
2750 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2751 if (wcaps == AC_WCAP_OUT_AMP)
2752 /* found a mono speaker with an amp,
2753 must be lfe */
2754 lfe_pin = pin;
2755 }
2756 }
2757 }
2758
2759 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002760 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002761 if (err < 0)
2762 return err;
2763 }
2764
2765 return 0;
2766}
2767
Mattc7d4b2f2005-06-27 14:59:41 +02002768static int stac9200_parse_auto_config(struct hda_codec *codec)
2769{
2770 struct sigmatel_spec *spec = codec->spec;
2771 int err;
2772
Kailang Yangdf694da2005-12-05 19:42:22 +01002773 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002774 return err;
2775
2776 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2777 return err;
2778
Takashi Iwai82bc9552006-03-21 11:24:42 +01002779 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2780 return err;
2781
Richard Fish160ea0d2006-09-06 13:58:25 +02002782 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2783 return err;
2784
Takashi Iwai82bc9552006-03-21 11:24:42 +01002785 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002786 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002787 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002788 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002789
2790 if (spec->kctl_alloc)
2791 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2792
2793 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002794 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002795
2796 return 1;
2797}
2798
Sam Revitch62fe78e2006-05-10 15:09:17 +02002799/*
2800 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2801 * funky external mute control using GPIO pins.
2802 */
2803
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002804static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
2805 unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002806{
2807 unsigned int gpiostate, gpiomask, gpiodir;
2808
2809 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2810 AC_VERB_GET_GPIO_DATA, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002811 gpiostate = (gpiostate & ~mask) | (data & mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002812
2813 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2814 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002815 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002816
2817 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2818 AC_VERB_GET_GPIO_DIRECTION, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002819 gpiodir |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002820
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002821 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002822 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2823
2824 snd_hda_codec_write(codec, codec->afg, 0,
2825 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002826 snd_hda_codec_read(codec, codec->afg, 0,
2827 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002828
2829 msleep(1);
2830
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002831 snd_hda_codec_read(codec, codec->afg, 0,
2832 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002833}
2834
Takashi Iwai314634b2006-09-21 11:56:18 +02002835static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2836 unsigned int event)
2837{
2838 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002839 snd_hda_codec_write_cache(codec, nid, 0,
2840 AC_VERB_SET_UNSOLICITED_ENABLE,
2841 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002842}
2843
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002844static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2845{
2846 int i;
2847 for (i = 0; i < cfg->hp_outs; i++)
2848 if (cfg->hp_pins[i] == nid)
2849 return 1; /* nid is a HP-Out */
2850
2851 return 0; /* nid is not a HP-Out */
2852};
2853
Mattc7d4b2f2005-06-27 14:59:41 +02002854static int stac92xx_init(struct hda_codec *codec)
2855{
2856 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002857 struct auto_pin_cfg *cfg = &spec->autocfg;
2858 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002859
Mattc7d4b2f2005-06-27 14:59:41 +02002860 snd_hda_sequence_write(codec, spec->init);
2861
Takashi Iwai82bc9552006-03-21 11:24:42 +01002862 /* set up pins */
2863 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002864 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002865 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002866 enable_pin_detect(codec, cfg->hp_pins[i],
2867 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002868 /* force to enable the first line-out; the others are set up
2869 * in unsol_event
2870 */
2871 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2872 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002873 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002874 /* fake event to set up pins */
2875 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2876 } else {
2877 stac92xx_auto_init_multi_out(codec);
2878 stac92xx_auto_init_hp_out(codec);
2879 }
2880 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002881 hda_nid_t nid = cfg->input_pins[i];
2882 if (nid) {
2883 unsigned int pinctl = AC_PINCTL_IN_EN;
2884 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2885 pinctl |= stac92xx_get_vref(codec, nid);
2886 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2887 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002888 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002889 for (i = 0; i < spec->num_dmics; i++)
2890 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2891 AC_PINCTL_IN_EN);
2892 for (i = 0; i < spec->num_pwrs; i++) {
2893 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2894 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2895 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2896 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2897 /* outputs are only ports capable of power management
2898 * any attempts on powering down a input port cause the
2899 * referenced VREF to act quirky.
2900 */
2901 if (pinctl & AC_PINCTL_IN_EN)
2902 continue;
2903 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2904 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2905 }
Matt Porter8b657272006-10-26 17:12:59 +02002906
Takashi Iwai82bc9552006-03-21 11:24:42 +01002907 if (cfg->dig_out_pin)
2908 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2909 AC_PINCTL_OUT_EN);
2910 if (cfg->dig_in_pin)
2911 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2912 AC_PINCTL_IN_EN);
2913
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002914 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002915
Mattc7d4b2f2005-06-27 14:59:41 +02002916 return 0;
2917}
2918
Matt2f2f4252005-04-13 14:45:30 +02002919static void stac92xx_free(struct hda_codec *codec)
2920{
Mattc7d4b2f2005-06-27 14:59:41 +02002921 struct sigmatel_spec *spec = codec->spec;
2922 int i;
2923
2924 if (! spec)
2925 return;
2926
2927 if (spec->kctl_alloc) {
2928 for (i = 0; i < spec->num_kctl_used; i++)
2929 kfree(spec->kctl_alloc[i].name);
2930 kfree(spec->kctl_alloc);
2931 }
2932
Richard Fish11b44bb2006-08-23 18:31:34 +02002933 if (spec->bios_pin_configs)
2934 kfree(spec->bios_pin_configs);
2935
Mattc7d4b2f2005-06-27 14:59:41 +02002936 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002937}
2938
Matt4e550962005-07-04 17:51:39 +02002939static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2940 unsigned int flag)
2941{
2942 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2943 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002944
Takashi Iwaif9acba42007-05-29 18:01:06 +02002945 if (pin_ctl & AC_PINCTL_IN_EN) {
2946 /*
2947 * we need to check the current set-up direction of
2948 * shared input pins since they can be switched via
2949 * "xxx as Output" mixer switch
2950 */
2951 struct sigmatel_spec *spec = codec->spec;
2952 struct auto_pin_cfg *cfg = &spec->autocfg;
2953 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2954 spec->line_switch) ||
2955 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2956 spec->mic_switch))
2957 return;
2958 }
2959
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002960 /* if setting pin direction bits, clear the current
2961 direction bits first */
2962 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2963 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2964
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002965 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002966 AC_VERB_SET_PIN_WIDGET_CONTROL,
2967 pin_ctl | flag);
2968}
2969
2970static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2971 unsigned int flag)
2972{
2973 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2974 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002975 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002976 AC_VERB_SET_PIN_WIDGET_CONTROL,
2977 pin_ctl & ~flag);
2978}
2979
Jiang Zhe40c1d302007-11-12 13:05:16 +01002980static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02002981{
2982 if (!nid)
2983 return 0;
2984 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01002985 & (1 << 31)) {
2986 unsigned int pinctl;
2987 pinctl = snd_hda_codec_read(codec, nid, 0,
2988 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2989 if (pinctl & AC_PINCTL_IN_EN)
2990 return 0; /* mic- or line-input */
2991 else
2992 return 1; /* HP-output */
2993 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002994 return 0;
2995}
2996
2997static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02002998{
2999 struct sigmatel_spec *spec = codec->spec;
3000 struct auto_pin_cfg *cfg = &spec->autocfg;
3001 int i, presence;
3002
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003003 presence = 0;
3004 for (i = 0; i < cfg->hp_outs; i++) {
Jiang Zhe40c1d302007-11-12 13:05:16 +01003005 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwai314634b2006-09-21 11:56:18 +02003006 if (presence)
3007 break;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003008 }
Matt4e550962005-07-04 17:51:39 +02003009
3010 if (presence) {
3011 /* disable lineouts, enable hp */
3012 for (i = 0; i < cfg->line_outs; i++)
3013 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3014 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003015 for (i = 0; i < cfg->speaker_outs; i++)
3016 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3017 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003018 } else {
3019 /* enable lineouts, disable hp */
3020 for (i = 0; i < cfg->line_outs; i++)
3021 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3022 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003023 for (i = 0; i < cfg->speaker_outs; i++)
3024 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3025 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003026 }
3027}
3028
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003029static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3030{
3031 struct sigmatel_spec *spec = codec->spec;
3032 hda_nid_t nid = spec->pwr_nids[idx];
3033 int presence, val;
3034 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3035 & 0x000000ff;
3036 presence = get_hp_pin_presence(codec, nid);
3037 idx = 1 << idx;
3038
3039 if (presence)
3040 val &= ~idx;
3041 else
3042 val |= idx;
3043
3044 /* power down unused output ports */
3045 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3046};
3047
Takashi Iwai314634b2006-09-21 11:56:18 +02003048static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3049{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003050 struct sigmatel_spec *spec = codec->spec;
3051 int idx = res >> 26 & 0x0f;
3052
3053 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003054 case STAC_HP_EVENT:
3055 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003056 /* fallthru */
3057 case STAC_PWR_EVENT:
3058 if (spec->num_pwrs > 0)
3059 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003060 }
3061}
3062
Takashi Iwaicb53c622007-08-10 17:21:45 +02003063#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003064static int stac92xx_resume(struct hda_codec *codec)
3065{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003066 struct sigmatel_spec *spec = codec->spec;
3067
Richard Fish11b44bb2006-08-23 18:31:34 +02003068 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003069 snd_hda_sequence_write(codec, spec->init);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003070 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003071 snd_hda_codec_resume_amp(codec);
3072 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003073 /* invoke unsolicited event to reset the HP state */
3074 if (spec->hp_detect)
3075 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003076 return 0;
3077}
3078#endif
3079
Matt2f2f4252005-04-13 14:45:30 +02003080static struct hda_codec_ops stac92xx_patch_ops = {
3081 .build_controls = stac92xx_build_controls,
3082 .build_pcms = stac92xx_build_pcms,
3083 .init = stac92xx_init,
3084 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003085 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003086#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003087 .resume = stac92xx_resume,
3088#endif
Matt2f2f4252005-04-13 14:45:30 +02003089};
3090
3091static int patch_stac9200(struct hda_codec *codec)
3092{
3093 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003094 int err;
Matt2f2f4252005-04-13 14:45:30 +02003095
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003096 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003097 if (spec == NULL)
3098 return -ENOMEM;
3099
3100 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003101 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003102 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003103 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3104 stac9200_models,
3105 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003106 if (spec->board_config < 0) {
3107 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3108 err = stac92xx_save_bios_config_regs(codec);
3109 if (err < 0) {
3110 stac92xx_free(codec);
3111 return err;
3112 }
3113 spec->pin_configs = spec->bios_pin_configs;
3114 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003115 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3116 stac92xx_set_config_regs(codec);
3117 }
Matt2f2f4252005-04-13 14:45:30 +02003118
3119 spec->multiout.max_channels = 2;
3120 spec->multiout.num_dacs = 1;
3121 spec->multiout.dac_nids = stac9200_dac_nids;
3122 spec->adc_nids = stac9200_adc_nids;
3123 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003124 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003125 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003126 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003127 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003128
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003129 if (spec->board_config == STAC_9200_GATEWAY)
3130 spec->init = stac9200_eapd_init;
3131 else
3132 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003133 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003134
3135 err = stac9200_parse_auto_config(codec);
3136 if (err < 0) {
3137 stac92xx_free(codec);
3138 return err;
3139 }
Matt2f2f4252005-04-13 14:45:30 +02003140
3141 codec->patch_ops = stac92xx_patch_ops;
3142
3143 return 0;
3144}
3145
Tobin Davis8e21c342007-01-08 11:04:17 +01003146static int patch_stac925x(struct hda_codec *codec)
3147{
3148 struct sigmatel_spec *spec;
3149 int err;
3150
3151 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3152 if (spec == NULL)
3153 return -ENOMEM;
3154
3155 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003156 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003157 spec->pin_nids = stac925x_pin_nids;
3158 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3159 stac925x_models,
3160 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003161 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003162 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003163 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3164 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003165 err = stac92xx_save_bios_config_regs(codec);
3166 if (err < 0) {
3167 stac92xx_free(codec);
3168 return err;
3169 }
3170 spec->pin_configs = spec->bios_pin_configs;
3171 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3172 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3173 stac92xx_set_config_regs(codec);
3174 }
3175
3176 spec->multiout.max_channels = 2;
3177 spec->multiout.num_dacs = 1;
3178 spec->multiout.dac_nids = stac925x_dac_nids;
3179 spec->adc_nids = stac925x_adc_nids;
3180 spec->mux_nids = stac925x_mux_nids;
3181 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003182 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003183 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003184 switch (codec->vendor_id) {
3185 case 0x83847632: /* STAC9202 */
3186 case 0x83847633: /* STAC9202D */
3187 case 0x83847636: /* STAC9251 */
3188 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003189 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003190 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003191 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3192 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003193 break;
3194 default:
3195 spec->num_dmics = 0;
3196 break;
3197 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003198
3199 spec->init = stac925x_core_init;
3200 spec->mixer = stac925x_mixer;
3201
3202 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003203 if (!err) {
3204 if (spec->board_config < 0) {
3205 printk(KERN_WARNING "hda_codec: No auto-config is "
3206 "available, default to model=ref\n");
3207 spec->board_config = STAC_925x_REF;
3208 goto again;
3209 }
3210 err = -EINVAL;
3211 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003212 if (err < 0) {
3213 stac92xx_free(codec);
3214 return err;
3215 }
3216
3217 codec->patch_ops = stac92xx_patch_ops;
3218
3219 return 0;
3220}
3221
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003222static struct hda_input_mux stac92hd73xx_dmux = {
3223 .num_items = 4,
3224 .items = {
3225 { "Analog Inputs", 0x0b },
3226 { "CD", 0x08 },
3227 { "Digital Mic 1", 0x09 },
3228 { "Digital Mic 2", 0x0a },
3229 }
3230};
3231
3232static int patch_stac92hd73xx(struct hda_codec *codec)
3233{
3234 struct sigmatel_spec *spec;
3235 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3236 int err = 0;
3237
3238 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3239 if (spec == NULL)
3240 return -ENOMEM;
3241
3242 codec->spec = spec;
3243 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3244 spec->pin_nids = stac92hd73xx_pin_nids;
3245 spec->board_config = snd_hda_check_board_config(codec,
3246 STAC_92HD73XX_MODELS,
3247 stac92hd73xx_models,
3248 stac92hd73xx_cfg_tbl);
3249again:
3250 if (spec->board_config < 0) {
3251 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3252 " STAC92HD73XX, using BIOS defaults\n");
3253 err = stac92xx_save_bios_config_regs(codec);
3254 if (err < 0) {
3255 stac92xx_free(codec);
3256 return err;
3257 }
3258 spec->pin_configs = spec->bios_pin_configs;
3259 } else {
3260 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3261 stac92xx_set_config_regs(codec);
3262 }
3263
3264 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3265 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3266
3267 if (spec->multiout.num_dacs < 0) {
3268 printk(KERN_WARNING "hda_codec: Could not determine "
3269 "number of channels defaulting to DAC count\n");
3270 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3271 }
3272
3273 switch (spec->multiout.num_dacs) {
3274 case 0x3: /* 6 Channel */
3275 spec->mixer = stac92hd73xx_6ch_mixer;
3276 spec->init = stac92hd73xx_6ch_core_init;
3277 break;
3278 case 0x4: /* 8 Channel */
3279 spec->multiout.hp_nid = 0x18;
3280 spec->mixer = stac92hd73xx_8ch_mixer;
3281 spec->init = stac92hd73xx_8ch_core_init;
3282 break;
3283 case 0x5: /* 10 Channel */
3284 spec->multiout.hp_nid = 0x19;
3285 spec->mixer = stac92hd73xx_10ch_mixer;
3286 spec->init = stac92hd73xx_10ch_core_init;
3287 };
3288
3289 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3290 spec->aloopback_mask = 0x01;
3291 spec->aloopback_shift = 8;
3292
3293 spec->mux_nids = stac92hd73xx_mux_nids;
3294 spec->adc_nids = stac92hd73xx_adc_nids;
3295 spec->dmic_nids = stac92hd73xx_dmic_nids;
3296 spec->dmux_nids = stac92hd73xx_dmux_nids;
3297
3298 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3299 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3300 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003301 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003302 spec->dinput_mux = &stac92hd73xx_dmux;
3303 /* GPIO0 High = Enable EAPD */
3304 spec->gpio_mask = spec->gpio_data = 0x000001;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003305
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003306 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3307 spec->pwr_nids = stac92hd73xx_pwr_nids;
3308
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003309 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3310
3311 if (!err) {
3312 if (spec->board_config < 0) {
3313 printk(KERN_WARNING "hda_codec: No auto-config is "
3314 "available, default to model=ref\n");
3315 spec->board_config = STAC_92HD73XX_REF;
3316 goto again;
3317 }
3318 err = -EINVAL;
3319 }
3320
3321 if (err < 0) {
3322 stac92xx_free(codec);
3323 return err;
3324 }
3325
3326 codec->patch_ops = stac92xx_patch_ops;
3327
3328 return 0;
3329}
3330
Matthew Ranostaye035b842007-11-06 11:53:55 +01003331static int patch_stac92hd71bxx(struct hda_codec *codec)
3332{
3333 struct sigmatel_spec *spec;
3334 int err = 0;
3335
3336 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3337 if (spec == NULL)
3338 return -ENOMEM;
3339
3340 codec->spec = spec;
3341 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3342 spec->pin_nids = stac92hd71bxx_pin_nids;
3343 spec->board_config = snd_hda_check_board_config(codec,
3344 STAC_92HD71BXX_MODELS,
3345 stac92hd71bxx_models,
3346 stac92hd71bxx_cfg_tbl);
3347again:
3348 if (spec->board_config < 0) {
3349 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3350 " STAC92HD71BXX, using BIOS defaults\n");
3351 err = stac92xx_save_bios_config_regs(codec);
3352 if (err < 0) {
3353 stac92xx_free(codec);
3354 return err;
3355 }
3356 spec->pin_configs = spec->bios_pin_configs;
3357 } else {
3358 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3359 stac92xx_set_config_regs(codec);
3360 }
3361
Matthew Ranostay541eee82007-12-14 12:08:04 +01003362 switch (codec->vendor_id) {
3363 case 0x111d76b6: /* 4 Port without Analog Mixer */
3364 case 0x111d76b7:
3365 case 0x111d76b4: /* 6 Port without Analog Mixer */
3366 case 0x111d76b5:
3367 spec->mixer = stac92hd71bxx_mixer;
3368 spec->init = stac92hd71bxx_core_init;
3369 break;
3370 default:
3371 spec->mixer = stac92hd71bxx_analog_mixer;
3372 spec->init = stac92hd71bxx_analog_core_init;
3373 }
3374
3375 spec->aloopback_mask = 0x20;
3376 spec->aloopback_shift = 0;
3377
Matthew Ranostaye035b842007-11-06 11:53:55 +01003378 spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
Matthew Ranostaye035b842007-11-06 11:53:55 +01003379
Matthew Ranostaye035b842007-11-06 11:53:55 +01003380 spec->mux_nids = stac92hd71bxx_mux_nids;
3381 spec->adc_nids = stac92hd71bxx_adc_nids;
3382 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003383 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003384
3385 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3386 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3387 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003388 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003389
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003390 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3391 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3392
Matthew Ranostaye035b842007-11-06 11:53:55 +01003393 spec->multiout.num_dacs = 2;
3394 spec->multiout.hp_nid = 0x11;
3395 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3396
3397 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3398 if (!err) {
3399 if (spec->board_config < 0) {
3400 printk(KERN_WARNING "hda_codec: No auto-config is "
3401 "available, default to model=ref\n");
3402 spec->board_config = STAC_92HD71BXX_REF;
3403 goto again;
3404 }
3405 err = -EINVAL;
3406 }
3407
3408 if (err < 0) {
3409 stac92xx_free(codec);
3410 return err;
3411 }
3412
3413 codec->patch_ops = stac92xx_patch_ops;
3414
3415 return 0;
3416};
3417
Matt2f2f4252005-04-13 14:45:30 +02003418static int patch_stac922x(struct hda_codec *codec)
3419{
3420 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003421 int err;
Matt2f2f4252005-04-13 14:45:30 +02003422
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003423 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003424 if (spec == NULL)
3425 return -ENOMEM;
3426
3427 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003428 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003429 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003430 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3431 stac922x_models,
3432 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003433 if (spec->board_config == STAC_INTEL_MAC_V3) {
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003434 spec->gpio_mask = spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003435 /* Intel Macs have all same PCI SSID, so we need to check
3436 * codec SSID to distinguish the exact models
3437 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003438 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003439 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003440
3441 case 0x106b0800:
3442 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003443 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003444 case 0x106b0600:
3445 case 0x106b0700:
3446 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003447 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003448 case 0x106b0e00:
3449 case 0x106b0f00:
3450 case 0x106b1600:
3451 case 0x106b1700:
3452 case 0x106b0200:
3453 case 0x106b1e00:
3454 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003455 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003456 case 0x106b1a00:
3457 case 0x00000100:
3458 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003459 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003460 case 0x106b0a00:
3461 case 0x106b2200:
3462 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003463 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003464 }
3465 }
3466
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003467 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003468 if (spec->board_config < 0) {
3469 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3470 "using BIOS defaults\n");
3471 err = stac92xx_save_bios_config_regs(codec);
3472 if (err < 0) {
3473 stac92xx_free(codec);
3474 return err;
3475 }
3476 spec->pin_configs = spec->bios_pin_configs;
3477 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003478 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3479 stac92xx_set_config_regs(codec);
3480 }
Matt2f2f4252005-04-13 14:45:30 +02003481
Matt2f2f4252005-04-13 14:45:30 +02003482 spec->adc_nids = stac922x_adc_nids;
3483 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003484 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003485 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003486 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003487 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003488
3489 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003490 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003491
3492 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003493
Matt Porter3cc08dc2006-01-23 15:27:49 +01003494 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003495 if (!err) {
3496 if (spec->board_config < 0) {
3497 printk(KERN_WARNING "hda_codec: No auto-config is "
3498 "available, default to model=ref\n");
3499 spec->board_config = STAC_D945_REF;
3500 goto again;
3501 }
3502 err = -EINVAL;
3503 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003504 if (err < 0) {
3505 stac92xx_free(codec);
3506 return err;
3507 }
3508
3509 codec->patch_ops = stac92xx_patch_ops;
3510
Takashi Iwai807a46362007-05-29 19:01:37 +02003511 /* Fix Mux capture level; max to 2 */
3512 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3513 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3514 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3515 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3516 (0 << AC_AMPCAP_MUTE_SHIFT));
3517
Matt Porter3cc08dc2006-01-23 15:27:49 +01003518 return 0;
3519}
3520
3521static int patch_stac927x(struct hda_codec *codec)
3522{
3523 struct sigmatel_spec *spec;
3524 int err;
3525
3526 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3527 if (spec == NULL)
3528 return -ENOMEM;
3529
3530 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003531 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003532 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003533 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3534 stac927x_models,
3535 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003536 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003537 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3538 if (spec->board_config < 0)
3539 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3540 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003541 err = stac92xx_save_bios_config_regs(codec);
3542 if (err < 0) {
3543 stac92xx_free(codec);
3544 return err;
3545 }
3546 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003547 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003548 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3549 stac92xx_set_config_regs(codec);
3550 }
3551
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003552 spec->adc_nids = stac927x_adc_nids;
3553 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3554 spec->mux_nids = stac927x_mux_nids;
3555 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
3556 spec->multiout.dac_nids = spec->dac_nids;
3557
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003558 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003559 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003560 case STAC_D965_5ST:
3561 /* GPIO0 High = Enable EAPD */
3562 spec->gpio_mask = spec->gpio_data = 0x00000001;
3563 spec->num_dmics = 0;
3564
Tobin Davis93ed1502006-09-01 21:03:12 +02003565 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003566 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003567 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003568 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003569 /* correct the front output jack as a hp out */
3570 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003571 /* correct the front input jack as a mic */
3572 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3573 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003574 case STAC_DELL_3ST:
3575 /* GPIO2 High = Enable EAPD */
3576 spec->gpio_mask = spec->gpio_data = 0x00000004;
3577 spec->dmic_nids = stac927x_dmic_nids;
3578 spec->num_dmics = STAC927X_NUM_DMICS;
3579
Tobin Davis93ed1502006-09-01 21:03:12 +02003580 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003581 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003582 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003583 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003584 break;
3585 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003586 /* GPIO0 High = Enable EAPD */
3587 spec->gpio_mask = spec->gpio_data = 0x00000001;
3588 spec->num_dmics = 0;
3589
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003590 spec->init = stac927x_core_init;
3591 spec->mixer = stac927x_mixer;
3592 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003593
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003594 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003595 spec->aloopback_mask = 0x40;
3596 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003597
Matt Porter3cc08dc2006-01-23 15:27:49 +01003598 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003599 if (!err) {
3600 if (spec->board_config < 0) {
3601 printk(KERN_WARNING "hda_codec: No auto-config is "
3602 "available, default to model=ref\n");
3603 spec->board_config = STAC_D965_REF;
3604 goto again;
3605 }
3606 err = -EINVAL;
3607 }
Mattc7d4b2f2005-06-27 14:59:41 +02003608 if (err < 0) {
3609 stac92xx_free(codec);
3610 return err;
3611 }
Matt2f2f4252005-04-13 14:45:30 +02003612
3613 codec->patch_ops = stac92xx_patch_ops;
3614
Takashi Iwai52987652008-01-16 16:09:47 +01003615 /*
3616 * !!FIXME!!
3617 * The STAC927x seem to require fairly long delays for certain
3618 * command sequences. With too short delays (even if the answer
3619 * is set to RIRB properly), it results in the silence output
3620 * on some hardwares like Dell.
3621 *
3622 * The below flag enables the longer delay (see get_response
3623 * in hda_intel.c).
3624 */
3625 codec->bus->needs_damn_long_delay = 1;
3626
Matt2f2f4252005-04-13 14:45:30 +02003627 return 0;
3628}
3629
Matt Porterf3302a52006-07-31 12:49:34 +02003630static int patch_stac9205(struct hda_codec *codec)
3631{
3632 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003633 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003634
3635 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3636 if (spec == NULL)
3637 return -ENOMEM;
3638
3639 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003640 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003641 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003642 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3643 stac9205_models,
3644 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003645 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003646 if (spec->board_config < 0) {
3647 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3648 err = stac92xx_save_bios_config_regs(codec);
3649 if (err < 0) {
3650 stac92xx_free(codec);
3651 return err;
3652 }
3653 spec->pin_configs = spec->bios_pin_configs;
3654 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003655 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3656 stac92xx_set_config_regs(codec);
3657 }
3658
3659 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003660 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003661 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003662 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003663 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003664 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003665 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003666 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003667 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003668
3669 spec->init = stac9205_core_init;
3670 spec->mixer = stac9205_mixer;
3671
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003672 spec->aloopback_mask = 0x40;
3673 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003674 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003675
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003676 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003677 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003678 /* Enable SPDIF in/out */
3679 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3680 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003681
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003682 spec->gpio_mask = 0x0000000b;
3683 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
3684 * GPIO3 High = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003685 */
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003686 spec->gpio_data = 0x00000009;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003687 break;
3688 default:
3689 /* GPIO0 High = EAPD */
3690 spec->gpio_mask = spec->gpio_data = 0x00000001;
3691 break;
3692 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003693
Matt Porterf3302a52006-07-31 12:49:34 +02003694 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003695 if (!err) {
3696 if (spec->board_config < 0) {
3697 printk(KERN_WARNING "hda_codec: No auto-config is "
3698 "available, default to model=ref\n");
3699 spec->board_config = STAC_9205_REF;
3700 goto again;
3701 }
3702 err = -EINVAL;
3703 }
Matt Porterf3302a52006-07-31 12:49:34 +02003704 if (err < 0) {
3705 stac92xx_free(codec);
3706 return err;
3707 }
3708
3709 codec->patch_ops = stac92xx_patch_ops;
3710
3711 return 0;
3712}
3713
Matt2f2f4252005-04-13 14:45:30 +02003714/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003715 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003716 */
3717
Guillaume Munch99ccc562006-08-16 19:35:12 +02003718/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003719static hda_nid_t vaio_dacs[] = { 0x2 };
3720#define VAIO_HP_DAC 0x5
3721static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3722static hda_nid_t vaio_mux_nids[] = { 0x15 };
3723
3724static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003725 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003726 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003727 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003728 { "Mic Jack", 0x1 },
3729 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003730 { "PCM", 0x3 },
3731 }
3732};
3733
3734static struct hda_verb vaio_init[] = {
3735 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003736 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003737 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3738 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3739 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3740 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003741 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003742 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3743 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3744 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3745 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3746 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3747 {}
3748};
3749
Guillaume Munch6d859062006-08-22 17:15:47 +02003750static struct hda_verb vaio_ar_init[] = {
3751 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3752 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3753 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3754 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3755/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3756 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003757 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003758 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3759 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3760/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3761 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3762 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3763 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3764 {}
3765};
3766
Takashi Iwaidb064e52006-03-16 16:04:58 +01003767/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003768static struct hda_bind_ctls vaio_bind_master_vol = {
3769 .ops = &snd_hda_bind_vol,
3770 .values = {
3771 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3772 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3773 0
3774 },
3775};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003776
3777/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003778static struct hda_bind_ctls vaio_bind_master_sw = {
3779 .ops = &snd_hda_bind_sw,
3780 .values = {
3781 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3782 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3783 0,
3784 },
3785};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003786
3787static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003788 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3789 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003790 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3791 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3792 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3793 {
3794 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3795 .name = "Capture Source",
3796 .count = 1,
3797 .info = stac92xx_mux_enum_info,
3798 .get = stac92xx_mux_enum_get,
3799 .put = stac92xx_mux_enum_put,
3800 },
3801 {}
3802};
3803
Guillaume Munch6d859062006-08-22 17:15:47 +02003804static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003805 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3806 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003807 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3808 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3809 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3810 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3811 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3812 {
3813 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3814 .name = "Capture Source",
3815 .count = 1,
3816 .info = stac92xx_mux_enum_info,
3817 .get = stac92xx_mux_enum_get,
3818 .put = stac92xx_mux_enum_put,
3819 },
3820 {}
3821};
3822
3823static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003824 .build_controls = stac92xx_build_controls,
3825 .build_pcms = stac92xx_build_pcms,
3826 .init = stac92xx_init,
3827 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003828#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003829 .resume = stac92xx_resume,
3830#endif
3831};
3832
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003833static int stac9872_vaio_init(struct hda_codec *codec)
3834{
3835 int err;
3836
3837 err = stac92xx_init(codec);
3838 if (err < 0)
3839 return err;
3840 if (codec->patch_ops.unsol_event)
3841 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3842 return 0;
3843}
3844
3845static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3846{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003847 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003848 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3849 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3850 } else {
3851 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3852 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3853 }
3854}
3855
3856static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3857{
3858 switch (res >> 26) {
3859 case STAC_HP_EVENT:
3860 stac9872_vaio_hp_detect(codec, res);
3861 break;
3862 }
3863}
3864
3865static struct hda_codec_ops stac9872_vaio_patch_ops = {
3866 .build_controls = stac92xx_build_controls,
3867 .build_pcms = stac92xx_build_pcms,
3868 .init = stac9872_vaio_init,
3869 .free = stac92xx_free,
3870 .unsol_event = stac9872_vaio_unsol_event,
3871#ifdef CONFIG_PM
3872 .resume = stac92xx_resume,
3873#endif
3874};
3875
Guillaume Munch6d859062006-08-22 17:15:47 +02003876enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3877 CXD9872RD_VAIO,
3878 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3879 STAC9872AK_VAIO,
3880 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3881 STAC9872K_VAIO,
3882 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003883 CXD9872AKD_VAIO,
3884 STAC_9872_MODELS,
3885};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003886
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003887static const char *stac9872_models[STAC_9872_MODELS] = {
3888 [CXD9872RD_VAIO] = "vaio",
3889 [CXD9872AKD_VAIO] = "vaio-ar",
3890};
3891
3892static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3893 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3894 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3895 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003896 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003897 {}
3898};
3899
Guillaume Munch6d859062006-08-22 17:15:47 +02003900static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003901{
3902 struct sigmatel_spec *spec;
3903 int board_config;
3904
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003905 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3906 stac9872_models,
3907 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003908 if (board_config < 0)
3909 /* unknown config, let generic-parser do its job... */
3910 return snd_hda_parse_generic_codec(codec);
3911
3912 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3913 if (spec == NULL)
3914 return -ENOMEM;
3915
3916 codec->spec = spec;
3917 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003918 case CXD9872RD_VAIO:
3919 case STAC9872AK_VAIO:
3920 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003921 spec->mixer = vaio_mixer;
3922 spec->init = vaio_init;
3923 spec->multiout.max_channels = 2;
3924 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3925 spec->multiout.dac_nids = vaio_dacs;
3926 spec->multiout.hp_nid = VAIO_HP_DAC;
3927 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3928 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003929 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003930 spec->input_mux = &vaio_mux;
3931 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003932 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003933 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003934
3935 case CXD9872AKD_VAIO:
3936 spec->mixer = vaio_ar_mixer;
3937 spec->init = vaio_ar_init;
3938 spec->multiout.max_channels = 2;
3939 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3940 spec->multiout.dac_nids = vaio_dacs;
3941 spec->multiout.hp_nid = VAIO_HP_DAC;
3942 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003943 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02003944 spec->adc_nids = vaio_adcs;
3945 spec->input_mux = &vaio_mux;
3946 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003947 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003948 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003949 }
3950
Takashi Iwaidb064e52006-03-16 16:04:58 +01003951 return 0;
3952}
3953
3954
3955/*
Matt2f2f4252005-04-13 14:45:30 +02003956 * patch entries
3957 */
3958struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3959 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3960 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3961 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3962 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3963 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3964 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3965 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003966 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3967 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3968 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3969 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3970 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
3971 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01003972 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
3973 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
3974 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
3975 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
3976 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
3977 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
3978 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
3979 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
3980 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
3981 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01003982 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
3983 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
3984 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
3985 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
3986 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
3987 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02003988 /* The following does not take into account .id=0x83847661 when subsys =
3989 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
3990 * currently not fully supported.
3991 */
3992 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
3993 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
3994 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02003995 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
3996 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
3997 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
3998 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
3999 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4000 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4001 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4002 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004003 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4004 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004005 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004006 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4007 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4008 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4009 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4010 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4011 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4012 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4013 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4014 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004015 {} /* terminator */
4016};