blob: 24137bc975c435efa212a8022294151a95332e2a [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 */
134 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100135 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200136
137 /* capture */
138 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200139 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200140 hda_nid_t *mux_nids;
141 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200142 hda_nid_t *dmic_nids;
143 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100144 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100145 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200146 hda_nid_t dig_in_nid;
Matt2f2f4252005-04-13 14:45:30 +0200147
Matt2f2f4252005-04-13 14:45:30 +0200148 /* pin widgets */
149 hda_nid_t *pin_nids;
150 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200151 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200152 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200153
154 /* codec specific stuff */
155 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100156 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200157
158 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200159 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100160 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200161 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100162 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200163
Matt Porter403d1942005-11-29 15:00:51 +0100164 /* i/o switches */
165 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200166 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200167 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200168
Mattc7d4b2f2005-06-27 14:59:41 +0200169 struct hda_pcm pcm_rec[2]; /* PCM information */
170
171 /* dynamic controls and input_mux */
172 struct auto_pin_cfg autocfg;
173 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100174 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200175 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200176 struct hda_input_mux private_imux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100177
178 /* virtual master */
179 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200180};
181
182static hda_nid_t stac9200_adc_nids[1] = {
183 0x03,
184};
185
186static hda_nid_t stac9200_mux_nids[1] = {
187 0x0c,
188};
189
190static hda_nid_t stac9200_dac_nids[1] = {
191 0x02,
192};
193
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100194static hda_nid_t stac92hd73xx_pwr_nids[8] = {
195 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
196 0x0f, 0x10, 0x11
197};
198
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100199static hda_nid_t stac92hd73xx_adc_nids[2] = {
200 0x1a, 0x1b
201};
202
203#define STAC92HD73XX_NUM_DMICS 2
204static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
205 0x13, 0x14, 0
206};
207
208#define STAC92HD73_DAC_COUNT 5
209static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
210 0x15, 0x16, 0x17, 0x18, 0x19,
211};
212
213static hda_nid_t stac92hd73xx_mux_nids[4] = {
214 0x28, 0x29, 0x2a, 0x2b,
215};
216
217static hda_nid_t stac92hd73xx_dmux_nids[2] = {
218 0x20, 0x21,
219};
220
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100221static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
222 0x0a, 0x0d, 0x0f
223};
224
Matthew Ranostaye035b842007-11-06 11:53:55 +0100225static hda_nid_t stac92hd71bxx_adc_nids[2] = {
226 0x12, 0x13,
227};
228
229static hda_nid_t stac92hd71bxx_mux_nids[2] = {
230 0x1a, 0x1b
231};
232
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100233static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
234 0x1c,
235};
236
Matthew Ranostaye035b842007-11-06 11:53:55 +0100237static hda_nid_t stac92hd71bxx_dac_nids[2] = {
238 0x10, /*0x11, */
239};
240
241#define STAC92HD71BXX_NUM_DMICS 2
242static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
243 0x18, 0x19, 0
244};
245
Tobin Davis8e21c342007-01-08 11:04:17 +0100246static hda_nid_t stac925x_adc_nids[1] = {
247 0x03,
248};
249
250static hda_nid_t stac925x_mux_nids[1] = {
251 0x0f,
252};
253
254static hda_nid_t stac925x_dac_nids[1] = {
255 0x02,
256};
257
Takashi Iwaif6e98522007-10-16 14:27:04 +0200258#define STAC925X_NUM_DMICS 1
259static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
260 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200261};
262
Takashi Iwai1697055e2007-12-18 18:05:52 +0100263static hda_nid_t stac925x_dmux_nids[1] = {
264 0x14,
265};
266
Matt2f2f4252005-04-13 14:45:30 +0200267static hda_nid_t stac922x_adc_nids[2] = {
268 0x06, 0x07,
269};
270
271static hda_nid_t stac922x_mux_nids[2] = {
272 0x12, 0x13,
273};
274
Matt Porter3cc08dc2006-01-23 15:27:49 +0100275static hda_nid_t stac927x_adc_nids[3] = {
276 0x07, 0x08, 0x09
277};
278
279static hda_nid_t stac927x_mux_nids[3] = {
280 0x15, 0x16, 0x17
281};
282
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100283static hda_nid_t stac927x_dmux_nids[1] = {
284 0x1b,
285};
286
Matthew Ranostay7f168592007-10-18 17:38:17 +0200287#define STAC927X_NUM_DMICS 2
288static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
289 0x13, 0x14, 0
290};
291
Matt Porterf3302a52006-07-31 12:49:34 +0200292static hda_nid_t stac9205_adc_nids[2] = {
293 0x12, 0x13
294};
295
296static hda_nid_t stac9205_mux_nids[2] = {
297 0x19, 0x1a
298};
299
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100300static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100301 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100302};
303
Takashi Iwaif6e98522007-10-16 14:27:04 +0200304#define STAC9205_NUM_DMICS 2
305static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
306 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200307};
308
Mattc7d4b2f2005-06-27 14:59:41 +0200309static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200310 0x08, 0x09, 0x0d, 0x0e,
311 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200312};
313
Tobin Davis8e21c342007-01-08 11:04:17 +0100314static hda_nid_t stac925x_pin_nids[8] = {
315 0x07, 0x08, 0x0a, 0x0b,
316 0x0c, 0x0d, 0x10, 0x11,
317};
318
Matt2f2f4252005-04-13 14:45:30 +0200319static hda_nid_t stac922x_pin_nids[10] = {
320 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
321 0x0f, 0x10, 0x11, 0x15, 0x1b,
322};
323
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100324static hda_nid_t stac92hd73xx_pin_nids[12] = {
325 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
326 0x0f, 0x10, 0x11, 0x12, 0x13,
327 0x14, 0x22
328};
329
Matthew Ranostaye035b842007-11-06 11:53:55 +0100330static hda_nid_t stac92hd71bxx_pin_nids[10] = {
331 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
332 0x0f, 0x14, 0x18, 0x19, 0x1e,
333};
334
Matt Porter3cc08dc2006-01-23 15:27:49 +0100335static hda_nid_t stac927x_pin_nids[14] = {
336 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
337 0x0f, 0x10, 0x11, 0x12, 0x13,
338 0x14, 0x21, 0x22, 0x23,
339};
340
Matt Porterf3302a52006-07-31 12:49:34 +0200341static hda_nid_t stac9205_pin_nids[12] = {
342 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
343 0x0f, 0x14, 0x16, 0x17, 0x18,
344 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200345};
346
Matt Porter8b657272006-10-26 17:12:59 +0200347static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
348 struct snd_ctl_elem_info *uinfo)
349{
350 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
351 struct sigmatel_spec *spec = codec->spec;
352 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
353}
354
355static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
356 struct snd_ctl_elem_value *ucontrol)
357{
358 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
359 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100360 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200361
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100362 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200363 return 0;
364}
365
366static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
367 struct snd_ctl_elem_value *ucontrol)
368{
369 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
370 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100371 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200372
373 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100374 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200375}
376
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100377static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200378{
379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
380 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200381 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200382}
383
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100384static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200385{
386 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
387 struct sigmatel_spec *spec = codec->spec;
388 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
389
390 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
391 return 0;
392}
393
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100394static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200395{
396 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
397 struct sigmatel_spec *spec = codec->spec;
398 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
399
Mattc7d4b2f2005-06-27 14:59:41 +0200400 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200401 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
402}
403
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200404#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
405
406static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
407 struct snd_ctl_elem_value *ucontrol)
408{
409 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100410 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200411 struct sigmatel_spec *spec = codec->spec;
412
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100413 ucontrol->value.integer.value[0] = !!(spec->aloopback &
414 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200415 return 0;
416}
417
418static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
419 struct snd_ctl_elem_value *ucontrol)
420{
421 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
422 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100423 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200424 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100425 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200426
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100427 idx_val = spec->aloopback_mask << idx;
428 if (ucontrol->value.integer.value[0])
429 val = spec->aloopback | idx_val;
430 else
431 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100432 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200433 return 0;
434
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100435 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200436
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100437 /* Only return the bits defined by the shift value of the
438 * first two bytes of the mask
439 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200440 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100441 kcontrol->private_value & 0xFFFF, 0x0);
442 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200443
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100444 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200445 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100446 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200447 } else {
448 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100449 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200450 }
451
452 snd_hda_codec_write_cache(codec, codec->afg, 0,
453 kcontrol->private_value >> 16, dac_mode);
454
455 return 1;
456}
457
Mattc7d4b2f2005-06-27 14:59:41 +0200458static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200459 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200460 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200461 {}
462};
463
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200464static struct hda_verb stac9200_eapd_init[] = {
465 /* set dac0mux for dac converter */
466 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
467 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
468 {}
469};
470
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100471static struct hda_verb stac92hd73xx_6ch_core_init[] = {
472 /* set master volume and direct control */
473 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
474 /* setup audio connections */
475 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
476 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
477 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
478 /* setup adcs to point to mixer */
479 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
480 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100481 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
482 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
483 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
484 /* setup import muxs */
485 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
486 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
487 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
488 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
489 {}
490};
491
492static struct hda_verb stac92hd73xx_8ch_core_init[] = {
493 /* set master volume and direct control */
494 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
495 /* setup audio connections */
496 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
497 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
498 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
499 /* connect hp ports to dac3 */
500 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
501 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
502 /* setup adcs to point to mixer */
503 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
504 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100505 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
506 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
507 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
508 /* setup import muxs */
509 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
510 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
511 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
512 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
513 {}
514};
515
516static struct hda_verb stac92hd73xx_10ch_core_init[] = {
517 /* set master volume and direct control */
518 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
519 /* setup audio connections */
520 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
521 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
522 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
523 /* dac3 is connected to import3 mux */
524 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
525 /* connect hp ports to dac4 */
526 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
527 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
528 /* setup adcs to point to mixer */
529 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
530 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100531 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
532 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
533 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
534 /* setup import muxs */
535 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
536 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
537 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
538 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
539 {}
540};
541
Matthew Ranostaye035b842007-11-06 11:53:55 +0100542static struct hda_verb stac92hd71bxx_core_init[] = {
543 /* set master volume and direct control */
544 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
545 /* connect headphone jack to dac1 */
546 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100547 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
548 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
549 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
550 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
551 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100552};
553
554static struct hda_verb stac92hd71bxx_analog_core_init[] = {
555 /* set master volume and direct control */
556 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
557 /* connect headphone jack to dac1 */
558 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100559 /* connect ports 0d and 0f to audio mixer */
560 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
561 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100562 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100563 /* unmute dac0 input in audio mixer */
564 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100565 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
566 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
567 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
568 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100569 {}
570};
571
Tobin Davis8e21c342007-01-08 11:04:17 +0100572static struct hda_verb stac925x_core_init[] = {
573 /* set dac0mux for dac converter */
574 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
575 {}
576};
577
Mattc7d4b2f2005-06-27 14:59:41 +0200578static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200579 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200580 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200581 {}
582};
583
Tobin Davis93ed1502006-09-01 21:03:12 +0200584static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200585 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200586 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200587 /* unmute node 0x1b */
588 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
589 /* select node 0x03 as DAC */
590 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
591 {}
592};
593
Matt Porter3cc08dc2006-01-23 15:27:49 +0100594static struct hda_verb stac927x_core_init[] = {
595 /* set master volume and direct control */
596 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
597 {}
598};
599
Matt Porterf3302a52006-07-31 12:49:34 +0200600static struct hda_verb stac9205_core_init[] = {
601 /* set master volume and direct control */
602 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
603 {}
604};
605
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200606#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200607 { \
608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
609 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200610 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200611 .info = stac92xx_mux_enum_info, \
612 .get = stac92xx_mux_enum_get, \
613 .put = stac92xx_mux_enum_put, \
614 }
615
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100616#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200617 { \
618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
619 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100620 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200621 .info = stac92xx_aloopback_info, \
622 .get = stac92xx_aloopback_get, \
623 .put = stac92xx_aloopback_put, \
624 .private_value = verb_read | (verb_write << 16), \
625 }
626
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100627static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200628 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
629 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200630 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200631 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
632 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200633 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200634 { } /* end */
635};
636
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100637static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100638 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
639
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100640 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
641 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
642
643 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
644 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
645
646 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
647 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
648
649 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
650 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
651
652 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
653 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
654
655 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
656 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
657
658 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
659 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
660 { } /* end */
661};
662
663static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100664 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
665
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100666 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
667 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
668
669 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
670 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
671
672 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
673 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
674
675 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
676 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
677
678 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
679 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
680
681 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
682 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
683
684 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
685 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
686 { } /* end */
687};
688
689static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100690 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
691
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
693 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
694
695 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
696 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
697
698 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
699 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
700
701 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
702 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
703
704 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
705 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
706
707 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
708 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
709
710 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
711 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
712 { } /* end */
713};
714
Matthew Ranostay541eee82007-12-14 12:08:04 +0100715static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100716 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100717
Matthew Ranostay9b359472007-11-07 13:03:12 +0100718 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
719 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
720 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
721
722 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
723 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
724 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
725
726 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
727 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaya780c0a2008-01-09 12:30:20 +0100728
729 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x14, 0x1, 0, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100730 { } /* end */
731};
732
Matthew Ranostay541eee82007-12-14 12:08:04 +0100733static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100734 STAC_INPUT_SOURCE(2),
735 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
736
Matthew Ranostay541eee82007-12-14 12:08:04 +0100737 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
738 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
739 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
740
741 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
742 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
743 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
Matthew Ranostaya780c0a2008-01-09 12:30:20 +0100744
745 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x14, 0x1, 0, HDA_INPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +0100746 { } /* end */
747};
748
Tobin Davis8e21c342007-01-08 11:04:17 +0100749static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200750 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100751 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
752 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
753 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
754 { } /* end */
755};
756
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100757static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200758 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100759 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200760
761 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
762 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
763 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
764
765 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
766 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
767 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
768
769 { } /* end */
770};
771
772/* This needs to be generated dynamically based on sequence */
773static struct snd_kcontrol_new stac922x_mixer[] = {
774 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200775 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
776 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
777 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
778
779 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
780 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
781 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
782 { } /* end */
783};
784
785
786static struct snd_kcontrol_new stac927x_mixer[] = {
787 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100788 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200789
790 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
791 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
792 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
793
794 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
795 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
796 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
797
798 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
799 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
800 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200801 { } /* end */
802};
803
Takashi Iwai1697055e2007-12-18 18:05:52 +0100804static struct snd_kcontrol_new stac_dmux_mixer = {
805 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
806 .name = "Digital Input Source",
807 /* count set later */
808 .info = stac92xx_dmux_enum_info,
809 .get = stac92xx_dmux_enum_get,
810 .put = stac92xx_dmux_enum_put,
811};
812
Takashi Iwai2134ea42008-01-10 16:53:55 +0100813static const char *slave_vols[] = {
814 "Front Playback Volume",
815 "Surround Playback Volume",
816 "Center Playback Volume",
817 "LFE Playback Volume",
818 "Side Playback Volume",
819 "Headphone Playback Volume",
820 "Headphone Playback Volume",
821 "Speaker Playback Volume",
822 "External Speaker Playback Volume",
823 "Speaker2 Playback Volume",
824 NULL
825};
826
827static const char *slave_sws[] = {
828 "Front Playback Switch",
829 "Surround Playback Switch",
830 "Center Playback Switch",
831 "LFE Playback Switch",
832 "Side Playback Switch",
833 "Headphone Playback Switch",
834 "Headphone Playback Switch",
835 "Speaker Playback Switch",
836 "External Speaker Playback Switch",
837 "Speaker2 Playback Switch",
838 NULL
839};
840
Matt2f2f4252005-04-13 14:45:30 +0200841static int stac92xx_build_controls(struct hda_codec *codec)
842{
843 struct sigmatel_spec *spec = codec->spec;
844 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200845 int i;
Matt2f2f4252005-04-13 14:45:30 +0200846
847 err = snd_hda_add_new_ctls(codec, spec->mixer);
848 if (err < 0)
849 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200850
851 for (i = 0; i < spec->num_mixers; i++) {
852 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
853 if (err < 0)
854 return err;
855 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100856 if (spec->num_dmuxes > 0) {
857 stac_dmux_mixer.count = spec->num_dmuxes;
858 err = snd_ctl_add(codec->bus->card,
859 snd_ctl_new1(&stac_dmux_mixer, codec));
860 if (err < 0)
861 return err;
862 }
Mattc7d4b2f2005-06-27 14:59:41 +0200863
Mattdabbed62005-06-14 10:19:34 +0200864 if (spec->multiout.dig_out_nid) {
865 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
866 if (err < 0)
867 return err;
868 }
869 if (spec->dig_in_nid) {
870 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
871 if (err < 0)
872 return err;
873 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100874
875 /* if we have no master control, let's create it */
876 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
877 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
878 HDA_OUTPUT, spec->vmaster_tlv);
879 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
880 spec->vmaster_tlv, slave_vols);
881 if (err < 0)
882 return err;
883 }
884 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
885 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
886 NULL, slave_sws);
887 if (err < 0)
888 return err;
889 }
890
Mattdabbed62005-06-14 10:19:34 +0200891 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200892}
893
Matt Porter403d1942005-11-29 15:00:51 +0100894static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200895 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200896 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
897};
898
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200899/*
900 STAC 9200 pin configs for
901 102801A8
902 102801DE
903 102801E8
904*/
905static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200906 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
907 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200908};
909
910/*
911 STAC 9200 pin configs for
912 102801C0
913 102801C1
914*/
915static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200916 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
917 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200918};
919
920/*
921 STAC 9200 pin configs for
922 102801C4 (Dell Dimension E310)
923 102801C5
924 102801C7
925 102801D9
926 102801DA
927 102801E3
928*/
929static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200930 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
931 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200932};
933
934
935/*
936 STAC 9200-32 pin configs for
937 102801B5 (Dell Inspiron 630m)
938 102801D8 (Dell Inspiron 640m)
939*/
940static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200941 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
942 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200943};
944
945/*
946 STAC 9200-32 pin configs for
947 102801C2 (Dell Latitude D620)
948 102801C8
949 102801CC (Dell Latitude D820)
950 102801D4
951 102801D6
952*/
953static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200954 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
955 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200956};
957
958/*
959 STAC 9200-32 pin configs for
960 102801CE (Dell XPS M1710)
961 102801CF (Dell Precision M90)
962*/
963static unsigned int dell9200_m23_pin_configs[8] = {
964 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
965 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
966};
967
968/*
969 STAC 9200-32 pin configs for
970 102801C9
971 102801CA
972 102801CB (Dell Latitude 120L)
973 102801D3
974*/
975static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200976 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
977 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200978};
979
980/*
981 STAC 9200-32 pin configs for
982 102801BD (Dell Inspiron E1505n)
983 102801EE
984 102801EF
985*/
986static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200987 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
988 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200989};
990
991/*
992 STAC 9200-32 pin configs for
993 102801F5 (Dell Inspiron 1501)
994 102801F6
995*/
996static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200997 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
998 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200999};
1000
1001/*
1002 STAC 9200-32
1003 102801CD (Dell Inspiron E1705/9400)
1004*/
1005static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001006 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1007 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001008};
1009
1010
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001011static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1012 [STAC_REF] = ref9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001013 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1014 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1015 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1016 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1017 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1018 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1019 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1020 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1021 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1022 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001023};
1024
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001025static const char *stac9200_models[STAC_9200_MODELS] = {
1026 [STAC_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001027 [STAC_9200_DELL_D21] = "dell-d21",
1028 [STAC_9200_DELL_D22] = "dell-d22",
1029 [STAC_9200_DELL_D23] = "dell-d23",
1030 [STAC_9200_DELL_M21] = "dell-m21",
1031 [STAC_9200_DELL_M22] = "dell-m22",
1032 [STAC_9200_DELL_M23] = "dell-m23",
1033 [STAC_9200_DELL_M24] = "dell-m24",
1034 [STAC_9200_DELL_M25] = "dell-m25",
1035 [STAC_9200_DELL_M26] = "dell-m26",
1036 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001037 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001038};
1039
1040static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1041 /* SigmaTel reference board */
1042 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1043 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001044 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001045 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1046 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001047 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001048 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1049 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1050 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1051 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1052 "unknown Dell", STAC_9200_DELL_D22),
1053 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1054 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001055 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001056 "Dell Latitude D620", STAC_9200_DELL_M22),
1057 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1058 "unknown Dell", STAC_9200_DELL_D23),
1059 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1060 "unknown Dell", STAC_9200_DELL_D23),
1061 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1062 "unknown Dell", STAC_9200_DELL_M22),
1063 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1064 "unknown Dell", STAC_9200_DELL_M24),
1065 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1066 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001067 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001068 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001069 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001070 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001071 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001072 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001073 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001074 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001075 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001076 "Dell Precision M90", STAC_9200_DELL_M23),
1077 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1078 "unknown Dell", STAC_9200_DELL_M22),
1079 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1080 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001081 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001082 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001083 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001084 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1085 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1086 "unknown Dell", STAC_9200_DELL_D23),
1087 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1088 "unknown Dell", STAC_9200_DELL_D23),
1089 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1090 "unknown Dell", STAC_9200_DELL_D21),
1091 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1092 "unknown Dell", STAC_9200_DELL_D23),
1093 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1094 "unknown Dell", STAC_9200_DELL_D21),
1095 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1096 "unknown Dell", STAC_9200_DELL_M25),
1097 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1098 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001099 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001100 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1101 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1102 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001103 /* Panasonic */
1104 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001105 /* Gateway machines needs EAPD to be set on resume */
1106 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1107 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1108 STAC_9200_GATEWAY),
1109 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1110 STAC_9200_GATEWAY),
Matt Porter403d1942005-11-29 15:00:51 +01001111 {} /* terminator */
1112};
1113
Tobin Davis8e21c342007-01-08 11:04:17 +01001114static unsigned int ref925x_pin_configs[8] = {
1115 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1116 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
1117};
1118
1119static unsigned int stac925x_MA6_pin_configs[8] = {
1120 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1121 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1122};
1123
Tobin Davis2c11f952007-05-17 09:36:34 +02001124static unsigned int stac925x_PA6_pin_configs[8] = {
1125 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1126 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1127};
1128
Tobin Davis8e21c342007-01-08 11:04:17 +01001129static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001130 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1131 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001132};
1133
1134static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1135 [STAC_REF] = ref925x_pin_configs,
1136 [STAC_M2_2] = stac925xM2_2_pin_configs,
1137 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001138 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001139};
1140
1141static const char *stac925x_models[STAC_925x_MODELS] = {
1142 [STAC_REF] = "ref",
1143 [STAC_M2_2] = "m2-2",
1144 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001145 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001146};
1147
1148static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1149 /* SigmaTel reference board */
1150 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001151 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001152 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1153 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1154 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001155 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001156 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1157 {} /* terminator */
1158};
1159
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001160static unsigned int ref92hd73xx_pin_configs[12] = {
1161 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1162 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1163 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1164};
1165
1166static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1167 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1168};
1169
1170static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1171 [STAC_92HD73XX_REF] = "ref",
1172};
1173
1174static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1175 /* SigmaTel reference board */
1176 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1177 "DFI LanParty", STAC_92HD73XX_REF),
1178 {} /* terminator */
1179};
1180
Matthew Ranostaye035b842007-11-06 11:53:55 +01001181static unsigned int ref92hd71bxx_pin_configs[10] = {
1182 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
1183 0x0181302e, 0x01114010, 0x01a19020, 0x90a000f0,
1184 0x90a000f0, 0x01452050,
1185};
1186
1187static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1188 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1189};
1190
1191static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1192 [STAC_92HD71BXX_REF] = "ref",
1193};
1194
1195static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1196 /* SigmaTel reference board */
1197 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1198 "DFI LanParty", STAC_92HD71BXX_REF),
1199 {} /* terminator */
1200};
1201
Matt Porter403d1942005-11-29 15:00:51 +01001202static unsigned int ref922x_pin_configs[10] = {
1203 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1204 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001205 0x40000100, 0x40000100,
1206};
1207
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001208/*
1209 STAC 922X pin configs for
1210 102801A7
1211 102801AB
1212 102801A9
1213 102801D1
1214 102801D2
1215*/
1216static unsigned int dell_922x_d81_pin_configs[10] = {
1217 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1218 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1219 0x01813122, 0x400001f2,
1220};
1221
1222/*
1223 STAC 922X pin configs for
1224 102801AC
1225 102801D0
1226*/
1227static unsigned int dell_922x_d82_pin_configs[10] = {
1228 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1229 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1230 0x01813122, 0x400001f1,
1231};
1232
1233/*
1234 STAC 922X pin configs for
1235 102801BF
1236*/
1237static unsigned int dell_922x_m81_pin_configs[10] = {
1238 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1239 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1240 0x40C003f1, 0x405003f0,
1241};
1242
1243/*
1244 STAC 9221 A1 pin configs for
1245 102801D7 (Dell XPS M1210)
1246*/
1247static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001248 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1249 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001250 0x508003f3, 0x405003f4,
1251};
1252
Matt Porter403d1942005-11-29 15:00:51 +01001253static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001254 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001255 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1256 0x02a19120, 0x40000100,
1257};
1258
1259static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001260 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1261 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001262 0x02a19320, 0x40000100,
1263};
1264
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001265static unsigned int intel_mac_v1_pin_configs[10] = {
1266 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1267 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001268 0x400000fc, 0x400000fb,
1269};
1270
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001271static unsigned int intel_mac_v2_pin_configs[10] = {
1272 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1273 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001274 0x400000fc, 0x400000fb,
1275};
1276
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001277static unsigned int intel_mac_v3_pin_configs[10] = {
1278 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1279 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1280 0x400000fc, 0x400000fb,
1281};
1282
1283static unsigned int intel_mac_v4_pin_configs[10] = {
1284 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1285 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1286 0x400000fc, 0x400000fb,
1287};
1288
1289static unsigned int intel_mac_v5_pin_configs[10] = {
1290 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1291 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1292 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001293};
1294
Takashi Iwai76c08822007-06-19 12:17:42 +02001295
Takashi Iwai19039bd2006-06-28 15:52:16 +02001296static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001297 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001298 [STAC_D945GTP3] = d945gtp3_pin_configs,
1299 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001300 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1301 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1302 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1303 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1304 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001305 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001306 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1307 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1308 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1309 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1310 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1311 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001312 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1313 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1314 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1315 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001316};
1317
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001318static const char *stac922x_models[STAC_922X_MODELS] = {
1319 [STAC_D945_REF] = "ref",
1320 [STAC_D945GTP5] = "5stack",
1321 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001322 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1323 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1324 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1325 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1326 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001327 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001328 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001329 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001330 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1331 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001332 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001333 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001334 [STAC_922X_DELL_D81] = "dell-d81",
1335 [STAC_922X_DELL_D82] = "dell-d82",
1336 [STAC_922X_DELL_M81] = "dell-m81",
1337 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001338};
1339
1340static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1341 /* SigmaTel reference board */
1342 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1343 "DFI LanParty", STAC_D945_REF),
1344 /* Intel 945G based systems */
1345 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1346 "Intel D945G", STAC_D945GTP3),
1347 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1348 "Intel D945G", STAC_D945GTP3),
1349 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1350 "Intel D945G", STAC_D945GTP3),
1351 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1352 "Intel D945G", STAC_D945GTP3),
1353 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1354 "Intel D945G", STAC_D945GTP3),
1355 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1356 "Intel D945G", STAC_D945GTP3),
1357 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1358 "Intel D945G", STAC_D945GTP3),
1359 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1360 "Intel D945G", STAC_D945GTP3),
1361 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1362 "Intel D945G", STAC_D945GTP3),
1363 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1364 "Intel D945G", STAC_D945GTP3),
1365 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1366 "Intel D945G", STAC_D945GTP3),
1367 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1368 "Intel D945G", STAC_D945GTP3),
1369 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1370 "Intel D945G", STAC_D945GTP3),
1371 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1372 "Intel D945G", STAC_D945GTP3),
1373 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1374 "Intel D945G", STAC_D945GTP3),
1375 /* Intel D945G 5-stack systems */
1376 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1377 "Intel D945G", STAC_D945GTP5),
1378 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1379 "Intel D945G", STAC_D945GTP5),
1380 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1381 "Intel D945G", STAC_D945GTP5),
1382 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1383 "Intel D945G", STAC_D945GTP5),
1384 /* Intel 945P based systems */
1385 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1386 "Intel D945P", STAC_D945GTP3),
1387 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1388 "Intel D945P", STAC_D945GTP3),
1389 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1390 "Intel D945P", STAC_D945GTP3),
1391 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1392 "Intel D945P", STAC_D945GTP3),
1393 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1394 "Intel D945P", STAC_D945GTP3),
1395 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1396 "Intel D945P", STAC_D945GTP5),
1397 /* other systems */
1398 /* Apple Mac Mini (early 2006) */
1399 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001400 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001401 /* Dell systems */
1402 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1403 "unknown Dell", STAC_922X_DELL_D81),
1404 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1405 "unknown Dell", STAC_922X_DELL_D81),
1406 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1407 "unknown Dell", STAC_922X_DELL_D81),
1408 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1409 "unknown Dell", STAC_922X_DELL_D82),
1410 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1411 "unknown Dell", STAC_922X_DELL_M81),
1412 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1413 "unknown Dell", STAC_922X_DELL_D82),
1414 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1415 "unknown Dell", STAC_922X_DELL_D81),
1416 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1417 "unknown Dell", STAC_922X_DELL_D81),
1418 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1419 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001420 {} /* terminator */
1421};
1422
Matt Porter3cc08dc2006-01-23 15:27:49 +01001423static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001424 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1425 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1426 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1427 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001428};
1429
Tobin Davis93ed1502006-09-01 21:03:12 +02001430static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001431 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1432 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1433 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1434 0x40000100, 0x40000100
1435};
1436
Tobin Davis93ed1502006-09-01 21:03:12 +02001437static unsigned int d965_5st_pin_configs[14] = {
1438 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1439 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1440 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1441 0x40000100, 0x40000100
1442};
1443
Tobin Davis4ff076e2007-08-07 11:48:12 +02001444static unsigned int dell_3st_pin_configs[14] = {
1445 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1446 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001447 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001448 0x40c003fc, 0x40000100
1449};
1450
Tobin Davis93ed1502006-09-01 21:03:12 +02001451static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001452 [STAC_D965_REF] = ref927x_pin_configs,
1453 [STAC_D965_3ST] = d965_3st_pin_configs,
1454 [STAC_D965_5ST] = d965_5st_pin_configs,
1455 [STAC_DELL_3ST] = dell_3st_pin_configs,
1456 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001457};
1458
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001459static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001460 [STAC_D965_REF] = "ref",
1461 [STAC_D965_3ST] = "3stack",
1462 [STAC_D965_5ST] = "5stack",
1463 [STAC_DELL_3ST] = "dell-3stack",
1464 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001465};
1466
1467static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1468 /* SigmaTel reference board */
1469 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1470 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001471 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001472 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1473 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001474 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001475 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1476 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1477 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1478 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1479 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1480 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1481 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1482 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1483 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1484 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1485 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1486 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1487 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1488 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1489 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1490 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001491 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001492 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001493 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001494 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1495 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001496 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001497 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1498 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001499 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1500 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1501 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1502 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1503 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001505 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001506 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1507 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1509 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1510 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1511 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1514 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001515 {} /* terminator */
1516};
1517
Matt Porterf3302a52006-07-31 12:49:34 +02001518static unsigned int ref9205_pin_configs[12] = {
1519 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matt Porter8b657272006-10-26 17:12:59 +02001520 0x01813122, 0x01a19021, 0x40000100, 0x40000100,
1521 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001522};
1523
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001524/*
1525 STAC 9205 pin configs for
1526 102801F1
1527 102801F2
1528 102801FC
1529 102801FD
1530 10280204
1531 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001532 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001533*/
1534static unsigned int dell_9205_m42_pin_configs[12] = {
1535 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1536 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1537 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1538};
1539
1540/*
1541 STAC 9205 pin configs for
1542 102801F9
1543 102801FA
1544 102801FE
1545 102801FF (Dell Precision M4300)
1546 10280206
1547 10280200
1548 10280201
1549*/
1550static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001551 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1552 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1553 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1554};
1555
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001556static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001557 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1558 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1559 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1560};
1561
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001562static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001563 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001564 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1565 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1566 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001567};
1568
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001569static const char *stac9205_models[STAC_9205_MODELS] = {
1570 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001571 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001572 [STAC_9205_DELL_M43] = "dell-m43",
1573 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001574};
1575
1576static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1577 /* SigmaTel reference board */
1578 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1579 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001580 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1581 "unknown Dell", STAC_9205_DELL_M42),
1582 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1583 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001584 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001585 "Dell Precision", STAC_9205_DELL_M43),
1586 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1587 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001588 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1589 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001590 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1591 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001592 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1593 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001594 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1595 "unknown Dell", STAC_9205_DELL_M42),
1596 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1597 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001598 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1599 "Dell Precision", STAC_9205_DELL_M43),
1600 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001601 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001602 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1603 "Dell Precision", STAC_9205_DELL_M43),
1604 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1605 "Dell Inspiron", STAC_9205_DELL_M44),
1606 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1607 "Dell Inspiron", STAC_9205_DELL_M44),
1608 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1609 "Dell Inspiron", STAC_9205_DELL_M44),
1610 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1611 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001612 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1613 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001614 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1615 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001616 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1617 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001618 {} /* terminator */
1619};
1620
Richard Fish11b44bb2006-08-23 18:31:34 +02001621static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1622{
1623 int i;
1624 struct sigmatel_spec *spec = codec->spec;
1625
1626 if (! spec->bios_pin_configs) {
1627 spec->bios_pin_configs = kcalloc(spec->num_pins,
1628 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1629 if (! spec->bios_pin_configs)
1630 return -ENOMEM;
1631 }
1632
1633 for (i = 0; i < spec->num_pins; i++) {
1634 hda_nid_t nid = spec->pin_nids[i];
1635 unsigned int pin_cfg;
1636
1637 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1638 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1639 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1640 nid, pin_cfg);
1641 spec->bios_pin_configs[i] = pin_cfg;
1642 }
1643
1644 return 0;
1645}
1646
Matthew Ranostay87d48362007-07-17 11:52:24 +02001647static void stac92xx_set_config_reg(struct hda_codec *codec,
1648 hda_nid_t pin_nid, unsigned int pin_config)
1649{
1650 int i;
1651 snd_hda_codec_write(codec, pin_nid, 0,
1652 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1653 pin_config & 0x000000ff);
1654 snd_hda_codec_write(codec, pin_nid, 0,
1655 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1656 (pin_config & 0x0000ff00) >> 8);
1657 snd_hda_codec_write(codec, pin_nid, 0,
1658 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1659 (pin_config & 0x00ff0000) >> 16);
1660 snd_hda_codec_write(codec, pin_nid, 0,
1661 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1662 pin_config >> 24);
1663 i = snd_hda_codec_read(codec, pin_nid, 0,
1664 AC_VERB_GET_CONFIG_DEFAULT,
1665 0x00);
1666 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1667 pin_nid, i);
1668}
1669
Matt2f2f4252005-04-13 14:45:30 +02001670static void stac92xx_set_config_regs(struct hda_codec *codec)
1671{
1672 int i;
1673 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001674
Matthew Ranostay87d48362007-07-17 11:52:24 +02001675 if (!spec->pin_configs)
1676 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001677
Matthew Ranostay87d48362007-07-17 11:52:24 +02001678 for (i = 0; i < spec->num_pins; i++)
1679 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1680 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001681}
Matt2f2f4252005-04-13 14:45:30 +02001682
Matt2f2f4252005-04-13 14:45:30 +02001683/*
1684 * Analog playback callbacks
1685 */
1686static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1687 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001688 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001689{
1690 struct sigmatel_spec *spec = codec->spec;
1691 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1692}
1693
1694static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1695 struct hda_codec *codec,
1696 unsigned int stream_tag,
1697 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001698 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001699{
1700 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001701 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001702}
1703
1704static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1705 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001706 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001707{
1708 struct sigmatel_spec *spec = codec->spec;
1709 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1710}
1711
1712/*
Mattdabbed62005-06-14 10:19:34 +02001713 * Digital playback callbacks
1714 */
1715static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1716 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001717 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001718{
1719 struct sigmatel_spec *spec = codec->spec;
1720 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1721}
1722
1723static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1724 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001725 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001726{
1727 struct sigmatel_spec *spec = codec->spec;
1728 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1729}
1730
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001731static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1732 struct hda_codec *codec,
1733 unsigned int stream_tag,
1734 unsigned int format,
1735 struct snd_pcm_substream *substream)
1736{
1737 struct sigmatel_spec *spec = codec->spec;
1738 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1739 stream_tag, format, substream);
1740}
1741
Mattdabbed62005-06-14 10:19:34 +02001742
1743/*
Matt2f2f4252005-04-13 14:45:30 +02001744 * Analog capture callbacks
1745 */
1746static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1747 struct hda_codec *codec,
1748 unsigned int stream_tag,
1749 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001750 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001751{
1752 struct sigmatel_spec *spec = codec->spec;
1753
1754 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1755 stream_tag, 0, format);
1756 return 0;
1757}
1758
1759static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1760 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001761 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001762{
1763 struct sigmatel_spec *spec = codec->spec;
1764
1765 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1766 return 0;
1767}
1768
Mattdabbed62005-06-14 10:19:34 +02001769static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1770 .substreams = 1,
1771 .channels_min = 2,
1772 .channels_max = 2,
1773 /* NID is set in stac92xx_build_pcms */
1774 .ops = {
1775 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001776 .close = stac92xx_dig_playback_pcm_close,
1777 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001778 },
1779};
1780
1781static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1782 .substreams = 1,
1783 .channels_min = 2,
1784 .channels_max = 2,
1785 /* NID is set in stac92xx_build_pcms */
1786};
1787
Matt2f2f4252005-04-13 14:45:30 +02001788static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1789 .substreams = 1,
1790 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001791 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001792 .nid = 0x02, /* NID to query formats and rates */
1793 .ops = {
1794 .open = stac92xx_playback_pcm_open,
1795 .prepare = stac92xx_playback_pcm_prepare,
1796 .cleanup = stac92xx_playback_pcm_cleanup
1797 },
1798};
1799
Matt Porter3cc08dc2006-01-23 15:27:49 +01001800static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1801 .substreams = 1,
1802 .channels_min = 2,
1803 .channels_max = 2,
1804 .nid = 0x06, /* NID to query formats and rates */
1805 .ops = {
1806 .open = stac92xx_playback_pcm_open,
1807 .prepare = stac92xx_playback_pcm_prepare,
1808 .cleanup = stac92xx_playback_pcm_cleanup
1809 },
1810};
1811
Matt2f2f4252005-04-13 14:45:30 +02001812static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001813 .channels_min = 2,
1814 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001815 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001816 .ops = {
1817 .prepare = stac92xx_capture_pcm_prepare,
1818 .cleanup = stac92xx_capture_pcm_cleanup
1819 },
1820};
1821
1822static int stac92xx_build_pcms(struct hda_codec *codec)
1823{
1824 struct sigmatel_spec *spec = codec->spec;
1825 struct hda_pcm *info = spec->pcm_rec;
1826
1827 codec->num_pcms = 1;
1828 codec->pcm_info = info;
1829
Mattc7d4b2f2005-06-27 14:59:41 +02001830 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001831 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001832 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001833 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001834 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001835
1836 if (spec->alt_switch) {
1837 codec->num_pcms++;
1838 info++;
1839 info->name = "STAC92xx Analog Alt";
1840 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1841 }
Matt2f2f4252005-04-13 14:45:30 +02001842
Mattdabbed62005-06-14 10:19:34 +02001843 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1844 codec->num_pcms++;
1845 info++;
1846 info->name = "STAC92xx Digital";
1847 if (spec->multiout.dig_out_nid) {
1848 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1849 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1850 }
1851 if (spec->dig_in_nid) {
1852 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1853 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1854 }
1855 }
1856
Matt2f2f4252005-04-13 14:45:30 +02001857 return 0;
1858}
1859
Takashi Iwaic960a032006-03-23 17:06:28 +01001860static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1861{
1862 unsigned int pincap = snd_hda_param_read(codec, nid,
1863 AC_PAR_PIN_CAP);
1864 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1865 if (pincap & AC_PINCAP_VREF_100)
1866 return AC_PINCTL_VREF_100;
1867 if (pincap & AC_PINCAP_VREF_80)
1868 return AC_PINCTL_VREF_80;
1869 if (pincap & AC_PINCAP_VREF_50)
1870 return AC_PINCTL_VREF_50;
1871 if (pincap & AC_PINCAP_VREF_GRD)
1872 return AC_PINCTL_VREF_GRD;
1873 return 0;
1874}
1875
Matt Porter403d1942005-11-29 15:00:51 +01001876static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1877
1878{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001879 snd_hda_codec_write_cache(codec, nid, 0,
1880 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001881}
1882
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001883#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001884
1885static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1886{
1887 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1888 struct sigmatel_spec *spec = codec->spec;
1889 int io_idx = kcontrol-> private_value & 0xff;
1890
1891 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1892 return 0;
1893}
1894
1895static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1896{
1897 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1898 struct sigmatel_spec *spec = codec->spec;
1899 hda_nid_t nid = kcontrol->private_value >> 8;
1900 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001901 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001902
1903 spec->io_switch[io_idx] = val;
1904
1905 if (val)
1906 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001907 else {
1908 unsigned int pinctl = AC_PINCTL_IN_EN;
1909 if (io_idx) /* set VREF for mic */
1910 pinctl |= stac92xx_get_vref(codec, nid);
1911 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1912 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001913
1914 /* check the auto-mute again: we need to mute/unmute the speaker
1915 * appropriately according to the pin direction
1916 */
1917 if (spec->hp_detect)
1918 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1919
Matt Porter403d1942005-11-29 15:00:51 +01001920 return 1;
1921}
1922
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001923#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1924
1925static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1926 struct snd_ctl_elem_value *ucontrol)
1927{
1928 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1929 struct sigmatel_spec *spec = codec->spec;
1930
1931 ucontrol->value.integer.value[0] = spec->clfe_swap;
1932 return 0;
1933}
1934
1935static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1936 struct snd_ctl_elem_value *ucontrol)
1937{
1938 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1939 struct sigmatel_spec *spec = codec->spec;
1940 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001941 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001942
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001943 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001944 return 0;
1945
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001946 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001947
1948 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1949 spec->clfe_swap ? 0x4 : 0x0);
1950
1951 return 1;
1952}
1953
Matt Porter403d1942005-11-29 15:00:51 +01001954#define STAC_CODEC_IO_SWITCH(xname, xpval) \
1955 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1956 .name = xname, \
1957 .index = 0, \
1958 .info = stac92xx_io_switch_info, \
1959 .get = stac92xx_io_switch_get, \
1960 .put = stac92xx_io_switch_put, \
1961 .private_value = xpval, \
1962 }
1963
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001964#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
1965 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1966 .name = xname, \
1967 .index = 0, \
1968 .info = stac92xx_clfe_switch_info, \
1969 .get = stac92xx_clfe_switch_get, \
1970 .put = stac92xx_clfe_switch_put, \
1971 .private_value = xpval, \
1972 }
Matt Porter403d1942005-11-29 15:00:51 +01001973
Mattc7d4b2f2005-06-27 14:59:41 +02001974enum {
1975 STAC_CTL_WIDGET_VOL,
1976 STAC_CTL_WIDGET_MUTE,
Matt Porter403d1942005-11-29 15:00:51 +01001977 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001978 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02001979};
1980
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001981static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02001982 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
1983 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matt Porter403d1942005-11-29 15:00:51 +01001984 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001985 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02001986};
1987
1988/* add dynamic controls */
1989static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
1990{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001991 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02001992
1993 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
1994 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
1995
1996 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
1997 if (! knew)
1998 return -ENOMEM;
1999 if (spec->kctl_alloc) {
2000 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2001 kfree(spec->kctl_alloc);
2002 }
2003 spec->kctl_alloc = knew;
2004 spec->num_kctl_alloc = num;
2005 }
2006
2007 knew = &spec->kctl_alloc[spec->num_kctl_used];
2008 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002009 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002010 if (! knew->name)
2011 return -ENOMEM;
2012 knew->private_value = val;
2013 spec->num_kctl_used++;
2014 return 0;
2015}
2016
Matt Porter403d1942005-11-29 15:00:51 +01002017/* flag inputs as additional dynamic lineouts */
2018static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2019{
2020 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002021 unsigned int wcaps, wtype;
2022 int i, num_dacs = 0;
2023
2024 /* use the wcaps cache to count all DACs available for line-outs */
2025 for (i = 0; i < codec->num_nodes; i++) {
2026 wcaps = codec->wcaps[i];
2027 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002028
Steve Longerbeam7b043892007-05-03 20:50:03 +02002029 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2030 num_dacs++;
2031 }
Matt Porter403d1942005-11-29 15:00:51 +01002032
Steve Longerbeam7b043892007-05-03 20:50:03 +02002033 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2034
Matt Porter403d1942005-11-29 15:00:51 +01002035 switch (cfg->line_outs) {
2036 case 3:
2037 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002038 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002039 cfg->line_out_pins[cfg->line_outs] =
2040 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002041 spec->line_switch = 1;
2042 cfg->line_outs++;
2043 }
2044 break;
2045 case 2:
2046 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002047 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002048 cfg->line_out_pins[cfg->line_outs] =
2049 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002050 spec->line_switch = 1;
2051 cfg->line_outs++;
2052 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002053 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002054 cfg->line_out_pins[cfg->line_outs] =
2055 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002056 spec->mic_switch = 1;
2057 cfg->line_outs++;
2058 }
2059 break;
2060 case 1:
2061 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002062 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002063 cfg->line_out_pins[cfg->line_outs] =
2064 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002065 spec->line_switch = 1;
2066 cfg->line_outs++;
2067 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002068 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002069 cfg->line_out_pins[cfg->line_outs] =
2070 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002071 spec->mic_switch = 1;
2072 cfg->line_outs++;
2073 }
2074 break;
2075 }
2076
2077 return 0;
2078}
2079
Steve Longerbeam7b043892007-05-03 20:50:03 +02002080
2081static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2082{
2083 int i;
2084
2085 for (i = 0; i < spec->multiout.num_dacs; i++) {
2086 if (spec->multiout.dac_nids[i] == nid)
2087 return 1;
2088 }
2089
2090 return 0;
2091}
2092
Matt Porter3cc08dc2006-01-23 15:27:49 +01002093/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002094 * Fill in the dac_nids table from the parsed pin configuration
2095 * This function only works when every pin in line_out_pins[]
2096 * contains atleast one DAC in its connection list. Some 92xx
2097 * codecs are not connected directly to a DAC, such as the 9200
2098 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002099 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002100static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002101 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002102{
2103 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002104 int i, j, conn_len = 0;
2105 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2106 unsigned int wcaps, wtype;
2107
Mattc7d4b2f2005-06-27 14:59:41 +02002108 for (i = 0; i < cfg->line_outs; i++) {
2109 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002110 conn_len = snd_hda_get_connections(codec, nid, conn,
2111 HDA_MAX_CONNECTIONS);
2112 for (j = 0; j < conn_len; j++) {
2113 wcaps = snd_hda_param_read(codec, conn[j],
2114 AC_PAR_AUDIO_WIDGET_CAP);
2115 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002116 if (wtype != AC_WID_AUD_OUT ||
2117 (wcaps & AC_WCAP_DIGITAL))
2118 continue;
2119 /* conn[j] is a DAC routed to this line-out */
2120 if (!is_in_dac_nids(spec, conn[j]))
2121 break;
2122 }
2123
2124 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002125 if (spec->multiout.num_dacs > 0) {
2126 /* we have already working output pins,
2127 * so let's drop the broken ones again
2128 */
2129 cfg->line_outs = spec->multiout.num_dacs;
2130 break;
2131 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002132 /* error out, no available DAC found */
2133 snd_printk(KERN_ERR
2134 "%s: No available DAC for pin 0x%x\n",
2135 __func__, nid);
2136 return -ENODEV;
2137 }
2138
2139 spec->multiout.dac_nids[i] = conn[j];
2140 spec->multiout.num_dacs++;
2141 if (conn_len > 1) {
2142 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002143 snd_hda_codec_write_cache(codec, nid, 0,
2144 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002145
2146 }
Mattc7d4b2f2005-06-27 14:59:41 +02002147 }
2148
Steve Longerbeam7b043892007-05-03 20:50:03 +02002149 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2150 spec->multiout.num_dacs,
2151 spec->multiout.dac_nids[0],
2152 spec->multiout.dac_nids[1],
2153 spec->multiout.dac_nids[2],
2154 spec->multiout.dac_nids[3],
2155 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002156 return 0;
2157}
2158
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002159/* create volume control/switch for the given prefx type */
2160static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2161{
2162 char name[32];
2163 int err;
2164
2165 sprintf(name, "%s Playback Volume", pfx);
2166 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2167 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2168 if (err < 0)
2169 return err;
2170 sprintf(name, "%s Playback Switch", pfx);
2171 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2172 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2173 if (err < 0)
2174 return err;
2175 return 0;
2176}
2177
Mattc7d4b2f2005-06-27 14:59:41 +02002178/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002179static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002180 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002181{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002182 static const char *chname[4] = {
2183 "Front", "Surround", NULL /*CLFE*/, "Side"
2184 };
Mattc7d4b2f2005-06-27 14:59:41 +02002185 hda_nid_t nid;
2186 int i, err;
2187
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002188 struct sigmatel_spec *spec = codec->spec;
2189 unsigned int wid_caps;
2190
2191
Mattc7d4b2f2005-06-27 14:59:41 +02002192 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002193 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002194 continue;
2195
2196 nid = spec->multiout.dac_nids[i];
2197
2198 if (i == 2) {
2199 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002200 err = create_controls(spec, "Center", nid, 1);
2201 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002202 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002203 err = create_controls(spec, "LFE", nid, 2);
2204 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002205 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002206
2207 wid_caps = get_wcaps(codec, nid);
2208
2209 if (wid_caps & AC_WCAP_LR_SWAP) {
2210 err = stac92xx_add_control(spec,
2211 STAC_CTL_WIDGET_CLFE_SWITCH,
2212 "Swap Center/LFE Playback Switch", nid);
2213
2214 if (err < 0)
2215 return err;
2216 }
2217
Mattc7d4b2f2005-06-27 14:59:41 +02002218 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002219 err = create_controls(spec, chname[i], nid, 3);
2220 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002221 return err;
2222 }
2223 }
2224
Matt Porter403d1942005-11-29 15:00:51 +01002225 if (spec->line_switch)
2226 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
2227 return err;
2228
2229 if (spec->mic_switch)
2230 if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
2231 return err;
2232
Mattc7d4b2f2005-06-27 14:59:41 +02002233 return 0;
2234}
2235
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002236static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2237{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002238 if (is_in_dac_nids(spec, nid))
2239 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002240 if (spec->multiout.hp_nid == nid)
2241 return 1;
2242 return 0;
2243}
2244
2245static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2246{
2247 if (!spec->multiout.hp_nid)
2248 spec->multiout.hp_nid = nid;
2249 else if (spec->multiout.num_dacs > 4) {
2250 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2251 return 1;
2252 } else {
2253 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2254 spec->multiout.num_dacs++;
2255 }
2256 return 0;
2257}
2258
2259/* add playback controls for Speaker and HP outputs */
2260static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2261 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002262{
2263 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002264 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002265 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002266
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002267 old_num_dacs = spec->multiout.num_dacs;
2268 for (i = 0; i < cfg->hp_outs; i++) {
2269 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2270 if (wid_caps & AC_WCAP_UNSOL_CAP)
2271 spec->hp_detect = 1;
2272 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2273 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2274 if (check_in_dac_nids(spec, nid))
2275 nid = 0;
2276 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002277 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002278 add_spec_dacs(spec, nid);
2279 }
2280 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002281 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002282 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2283 if (check_in_dac_nids(spec, nid))
2284 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002285 if (! nid)
2286 continue;
2287 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002288 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002289 for (i = 0; i < cfg->line_outs; i++) {
2290 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2291 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2292 if (check_in_dac_nids(spec, nid))
2293 nid = 0;
2294 if (! nid)
2295 continue;
2296 add_spec_dacs(spec, nid);
2297 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002298 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2299 static const char *pfxs[] = {
2300 "Speaker", "External Speaker", "Speaker2",
2301 };
2302 err = create_controls(spec, pfxs[i - old_num_dacs],
2303 spec->multiout.dac_nids[i], 3);
2304 if (err < 0)
2305 return err;
2306 }
2307 if (spec->multiout.hp_nid) {
2308 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002309 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002310 pfx = "Master";
2311 else
2312 pfx = "Headphone";
2313 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2314 if (err < 0)
2315 return err;
2316 }
Mattc7d4b2f2005-06-27 14:59:41 +02002317
2318 return 0;
2319}
2320
Matt Porter8b657272006-10-26 17:12:59 +02002321/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002322static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002323 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2324 "Digital Mic 3", "Digital Mic 4"
2325};
2326
2327/* create playback/capture controls for input pins on dmic capable codecs */
2328static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2329 const struct auto_pin_cfg *cfg)
2330{
2331 struct sigmatel_spec *spec = codec->spec;
2332 struct hda_input_mux *dimux = &spec->private_dimux;
2333 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002334 int err, i, j;
2335 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002336
2337 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2338 dimux->items[dimux->num_items].index = 0;
2339 dimux->num_items++;
2340
2341 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002342 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002343 int index;
2344 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002345 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002346 unsigned int def_conf;
2347
2348 def_conf = snd_hda_codec_read(codec,
2349 spec->dmic_nids[i],
2350 0,
2351 AC_VERB_GET_CONFIG_DEFAULT,
2352 0);
2353 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2354 continue;
2355
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002356 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002357 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002358 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002359 con_lst,
2360 HDA_MAX_NUM_INPUTS);
2361 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002362 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002363 index = j;
2364 goto found;
2365 }
2366 continue;
2367found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002368 wcaps = get_wcaps(codec, nid);
2369
2370 if (wcaps & AC_WCAP_OUT_AMP) {
2371 sprintf(name, "%s Capture Volume",
2372 stac92xx_dmic_labels[dimux->num_items]);
2373
2374 err = stac92xx_add_control(spec,
2375 STAC_CTL_WIDGET_VOL,
2376 name,
2377 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2378 if (err < 0)
2379 return err;
2380 }
2381
Matt Porter8b657272006-10-26 17:12:59 +02002382 dimux->items[dimux->num_items].label =
2383 stac92xx_dmic_labels[dimux->num_items];
2384 dimux->items[dimux->num_items].index = index;
2385 dimux->num_items++;
2386 }
2387
2388 return 0;
2389}
2390
Mattc7d4b2f2005-06-27 14:59:41 +02002391/* create playback/capture controls for input pins */
2392static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2393{
2394 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002395 struct hda_input_mux *imux = &spec->private_imux;
2396 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2397 int i, j, k;
2398
2399 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002400 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002401
Takashi Iwai314634b2006-09-21 11:56:18 +02002402 if (!cfg->input_pins[i])
2403 continue;
2404 index = -1;
2405 for (j = 0; j < spec->num_muxes; j++) {
2406 int num_cons;
2407 num_cons = snd_hda_get_connections(codec,
2408 spec->mux_nids[j],
2409 con_lst,
2410 HDA_MAX_NUM_INPUTS);
2411 for (k = 0; k < num_cons; k++)
2412 if (con_lst[k] == cfg->input_pins[i]) {
2413 index = k;
2414 goto found;
2415 }
Mattc7d4b2f2005-06-27 14:59:41 +02002416 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002417 continue;
2418 found:
2419 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2420 imux->items[imux->num_items].index = index;
2421 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002422 }
2423
Steve Longerbeam7b043892007-05-03 20:50:03 +02002424 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002425 /*
2426 * Set the current input for the muxes.
2427 * The STAC9221 has two input muxes with identical source
2428 * NID lists. Hopefully this won't get confused.
2429 */
2430 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002431 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2432 AC_VERB_SET_CONNECT_SEL,
2433 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002434 }
2435 }
2436
Mattc7d4b2f2005-06-27 14:59:41 +02002437 return 0;
2438}
2439
Mattc7d4b2f2005-06-27 14:59:41 +02002440static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2441{
2442 struct sigmatel_spec *spec = codec->spec;
2443 int i;
2444
2445 for (i = 0; i < spec->autocfg.line_outs; i++) {
2446 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2447 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2448 }
2449}
2450
2451static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2452{
2453 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002454 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002455
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002456 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2457 hda_nid_t pin;
2458 pin = spec->autocfg.hp_pins[i];
2459 if (pin) /* connect to front */
2460 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2461 }
2462 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2463 hda_nid_t pin;
2464 pin = spec->autocfg.speaker_pins[i];
2465 if (pin) /* connect to front */
2466 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2467 }
Mattc7d4b2f2005-06-27 14:59:41 +02002468}
2469
Matt Porter3cc08dc2006-01-23 15:27:49 +01002470static 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 +02002471{
2472 struct sigmatel_spec *spec = codec->spec;
2473 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002474 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002475
Matt Porter8b657272006-10-26 17:12:59 +02002476 if ((err = snd_hda_parse_pin_def_config(codec,
2477 &spec->autocfg,
2478 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002479 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002480 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002481 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002482
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002483 /* If we have no real line-out pin and multiple hp-outs, HPs should
2484 * be set up as multi-channel outputs.
2485 */
2486 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2487 spec->autocfg.hp_outs > 1) {
2488 /* Copy hp_outs to line_outs, backup line_outs in
2489 * speaker_outs so that the following routines can handle
2490 * HP pins as primary outputs.
2491 */
2492 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2493 sizeof(spec->autocfg.line_out_pins));
2494 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2495 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2496 sizeof(spec->autocfg.hp_pins));
2497 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2498 hp_speaker_swap = 1;
2499 }
2500
Matt Porter403d1942005-11-29 15:00:51 +01002501 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2502 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002503 if (spec->multiout.num_dacs == 0)
2504 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2505 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002506
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002507 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2508
2509 if (err < 0)
2510 return err;
2511
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002512 if (hp_speaker_swap == 1) {
2513 /* Restore the hp_outs and line_outs */
2514 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2515 sizeof(spec->autocfg.line_out_pins));
2516 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2517 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2518 sizeof(spec->autocfg.speaker_pins));
2519 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2520 memset(spec->autocfg.speaker_pins, 0,
2521 sizeof(spec->autocfg.speaker_pins));
2522 spec->autocfg.speaker_outs = 0;
2523 }
2524
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002525 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2526
2527 if (err < 0)
2528 return err;
2529
2530 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2531
2532 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002533 return err;
2534
Matt Porter8b657272006-10-26 17:12:59 +02002535 if (spec->num_dmics > 0)
2536 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2537 &spec->autocfg)) < 0)
2538 return err;
2539
Mattc7d4b2f2005-06-27 14:59:41 +02002540 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002541 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002542 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002543
Takashi Iwai82bc9552006-03-21 11:24:42 +01002544 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002545 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002546 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002547 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002548
2549 if (spec->kctl_alloc)
2550 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2551
2552 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002553 if (!spec->dinput_mux)
2554 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002555
2556 return 1;
2557}
2558
Takashi Iwai82bc9552006-03-21 11:24:42 +01002559/* add playback controls for HP output */
2560static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2561 struct auto_pin_cfg *cfg)
2562{
2563 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002564 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002565 unsigned int wid_caps;
2566
2567 if (! pin)
2568 return 0;
2569
2570 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002571 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002572 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002573
2574 return 0;
2575}
2576
Richard Fish160ea0d2006-09-06 13:58:25 +02002577/* add playback controls for LFE output */
2578static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2579 struct auto_pin_cfg *cfg)
2580{
2581 struct sigmatel_spec *spec = codec->spec;
2582 int err;
2583 hda_nid_t lfe_pin = 0x0;
2584 int i;
2585
2586 /*
2587 * search speaker outs and line outs for a mono speaker pin
2588 * with an amp. If one is found, add LFE controls
2589 * for it.
2590 */
2591 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2592 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2593 unsigned long wcaps = get_wcaps(codec, pin);
2594 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2595 if (wcaps == AC_WCAP_OUT_AMP)
2596 /* found a mono speaker with an amp, must be lfe */
2597 lfe_pin = pin;
2598 }
2599
2600 /* if speaker_outs is 0, then speakers may be in line_outs */
2601 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2602 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2603 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2604 unsigned long cfg;
2605 cfg = snd_hda_codec_read(codec, pin, 0,
2606 AC_VERB_GET_CONFIG_DEFAULT,
2607 0x00);
2608 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2609 unsigned long wcaps = get_wcaps(codec, pin);
2610 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2611 if (wcaps == AC_WCAP_OUT_AMP)
2612 /* found a mono speaker with an amp,
2613 must be lfe */
2614 lfe_pin = pin;
2615 }
2616 }
2617 }
2618
2619 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002620 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002621 if (err < 0)
2622 return err;
2623 }
2624
2625 return 0;
2626}
2627
Mattc7d4b2f2005-06-27 14:59:41 +02002628static int stac9200_parse_auto_config(struct hda_codec *codec)
2629{
2630 struct sigmatel_spec *spec = codec->spec;
2631 int err;
2632
Kailang Yangdf694da2005-12-05 19:42:22 +01002633 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002634 return err;
2635
2636 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2637 return err;
2638
Takashi Iwai82bc9552006-03-21 11:24:42 +01002639 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2640 return err;
2641
Richard Fish160ea0d2006-09-06 13:58:25 +02002642 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2643 return err;
2644
Takashi Iwai82bc9552006-03-21 11:24:42 +01002645 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002646 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002647 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002648 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002649
2650 if (spec->kctl_alloc)
2651 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2652
2653 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002654 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002655
2656 return 1;
2657}
2658
Sam Revitch62fe78e2006-05-10 15:09:17 +02002659/*
2660 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2661 * funky external mute control using GPIO pins.
2662 */
2663
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002664static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
2665 unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002666{
2667 unsigned int gpiostate, gpiomask, gpiodir;
2668
2669 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2670 AC_VERB_GET_GPIO_DATA, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002671 gpiostate = (gpiostate & ~mask) | (data & mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002672
2673 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2674 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002675 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002676
2677 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2678 AC_VERB_GET_GPIO_DIRECTION, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002679 gpiodir |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002680
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002681 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002682 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2683
2684 snd_hda_codec_write(codec, codec->afg, 0,
2685 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002686 snd_hda_codec_read(codec, codec->afg, 0,
2687 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002688
2689 msleep(1);
2690
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002691 snd_hda_codec_read(codec, codec->afg, 0,
2692 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002693}
2694
Takashi Iwai314634b2006-09-21 11:56:18 +02002695static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2696 unsigned int event)
2697{
2698 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002699 snd_hda_codec_write_cache(codec, nid, 0,
2700 AC_VERB_SET_UNSOLICITED_ENABLE,
2701 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002702}
2703
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002704static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2705{
2706 int i;
2707 for (i = 0; i < cfg->hp_outs; i++)
2708 if (cfg->hp_pins[i] == nid)
2709 return 1; /* nid is a HP-Out */
2710
2711 return 0; /* nid is not a HP-Out */
2712};
2713
Mattc7d4b2f2005-06-27 14:59:41 +02002714static int stac92xx_init(struct hda_codec *codec)
2715{
2716 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002717 struct auto_pin_cfg *cfg = &spec->autocfg;
2718 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002719
Mattc7d4b2f2005-06-27 14:59:41 +02002720 snd_hda_sequence_write(codec, spec->init);
2721
Takashi Iwai82bc9552006-03-21 11:24:42 +01002722 /* set up pins */
2723 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002724 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002725 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002726 enable_pin_detect(codec, cfg->hp_pins[i],
2727 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002728 /* force to enable the first line-out; the others are set up
2729 * in unsol_event
2730 */
2731 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2732 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002733 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002734 /* fake event to set up pins */
2735 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2736 } else {
2737 stac92xx_auto_init_multi_out(codec);
2738 stac92xx_auto_init_hp_out(codec);
2739 }
2740 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002741 hda_nid_t nid = cfg->input_pins[i];
2742 if (nid) {
2743 unsigned int pinctl = AC_PINCTL_IN_EN;
2744 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2745 pinctl |= stac92xx_get_vref(codec, nid);
2746 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2747 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002748 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002749 for (i = 0; i < spec->num_dmics; i++)
2750 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2751 AC_PINCTL_IN_EN);
2752 for (i = 0; i < spec->num_pwrs; i++) {
2753 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2754 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2755 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2756 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2757 /* outputs are only ports capable of power management
2758 * any attempts on powering down a input port cause the
2759 * referenced VREF to act quirky.
2760 */
2761 if (pinctl & AC_PINCTL_IN_EN)
2762 continue;
2763 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2764 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2765 }
Matt Porter8b657272006-10-26 17:12:59 +02002766
Takashi Iwai82bc9552006-03-21 11:24:42 +01002767 if (cfg->dig_out_pin)
2768 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2769 AC_PINCTL_OUT_EN);
2770 if (cfg->dig_in_pin)
2771 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2772 AC_PINCTL_IN_EN);
2773
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002774 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002775
Mattc7d4b2f2005-06-27 14:59:41 +02002776 return 0;
2777}
2778
Matt2f2f4252005-04-13 14:45:30 +02002779static void stac92xx_free(struct hda_codec *codec)
2780{
Mattc7d4b2f2005-06-27 14:59:41 +02002781 struct sigmatel_spec *spec = codec->spec;
2782 int i;
2783
2784 if (! spec)
2785 return;
2786
2787 if (spec->kctl_alloc) {
2788 for (i = 0; i < spec->num_kctl_used; i++)
2789 kfree(spec->kctl_alloc[i].name);
2790 kfree(spec->kctl_alloc);
2791 }
2792
Richard Fish11b44bb2006-08-23 18:31:34 +02002793 if (spec->bios_pin_configs)
2794 kfree(spec->bios_pin_configs);
2795
Mattc7d4b2f2005-06-27 14:59:41 +02002796 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002797}
2798
Matt4e550962005-07-04 17:51:39 +02002799static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2800 unsigned int flag)
2801{
2802 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2803 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002804
Takashi Iwaif9acba42007-05-29 18:01:06 +02002805 if (pin_ctl & AC_PINCTL_IN_EN) {
2806 /*
2807 * we need to check the current set-up direction of
2808 * shared input pins since they can be switched via
2809 * "xxx as Output" mixer switch
2810 */
2811 struct sigmatel_spec *spec = codec->spec;
2812 struct auto_pin_cfg *cfg = &spec->autocfg;
2813 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2814 spec->line_switch) ||
2815 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2816 spec->mic_switch))
2817 return;
2818 }
2819
Steve Longerbeam7b043892007-05-03 20:50:03 +02002820 /* if setting pin direction bits, clear the current
2821 direction bits first */
2822 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2823 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2824
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002825 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002826 AC_VERB_SET_PIN_WIDGET_CONTROL,
2827 pin_ctl | flag);
2828}
2829
2830static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2831 unsigned int flag)
2832{
2833 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2834 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002835 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002836 AC_VERB_SET_PIN_WIDGET_CONTROL,
2837 pin_ctl & ~flag);
2838}
2839
Jiang Zhe40c1d302007-11-12 13:05:16 +01002840static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02002841{
2842 if (!nid)
2843 return 0;
2844 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01002845 & (1 << 31)) {
2846 unsigned int pinctl;
2847 pinctl = snd_hda_codec_read(codec, nid, 0,
2848 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2849 if (pinctl & AC_PINCTL_IN_EN)
2850 return 0; /* mic- or line-input */
2851 else
2852 return 1; /* HP-output */
2853 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002854 return 0;
2855}
2856
2857static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02002858{
2859 struct sigmatel_spec *spec = codec->spec;
2860 struct auto_pin_cfg *cfg = &spec->autocfg;
2861 int i, presence;
2862
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002863 presence = 0;
2864 for (i = 0; i < cfg->hp_outs; i++) {
Jiang Zhe40c1d302007-11-12 13:05:16 +01002865 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwai314634b2006-09-21 11:56:18 +02002866 if (presence)
2867 break;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002868 }
Matt4e550962005-07-04 17:51:39 +02002869
2870 if (presence) {
2871 /* disable lineouts, enable hp */
2872 for (i = 0; i < cfg->line_outs; i++)
2873 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
2874 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002875 for (i = 0; i < cfg->speaker_outs; i++)
2876 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
2877 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002878 } else {
2879 /* enable lineouts, disable hp */
2880 for (i = 0; i < cfg->line_outs; i++)
2881 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
2882 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002883 for (i = 0; i < cfg->speaker_outs; i++)
2884 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
2885 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02002886 }
2887}
2888
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002889static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
2890{
2891 struct sigmatel_spec *spec = codec->spec;
2892 hda_nid_t nid = spec->pwr_nids[idx];
2893 int presence, val;
2894 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
2895 & 0x000000ff;
2896 presence = get_hp_pin_presence(codec, nid);
2897 idx = 1 << idx;
2898
2899 if (presence)
2900 val &= ~idx;
2901 else
2902 val |= idx;
2903
2904 /* power down unused output ports */
2905 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
2906};
2907
Takashi Iwai314634b2006-09-21 11:56:18 +02002908static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
2909{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002910 struct sigmatel_spec *spec = codec->spec;
2911 int idx = res >> 26 & 0x0f;
2912
2913 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002914 case STAC_HP_EVENT:
2915 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002916 /* fallthru */
2917 case STAC_PWR_EVENT:
2918 if (spec->num_pwrs > 0)
2919 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02002920 }
2921}
2922
Takashi Iwaicb53c622007-08-10 17:21:45 +02002923#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002924static int stac92xx_resume(struct hda_codec *codec)
2925{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002926 struct sigmatel_spec *spec = codec->spec;
2927
Richard Fish11b44bb2006-08-23 18:31:34 +02002928 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002929 snd_hda_sequence_write(codec, spec->init);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002930 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002931 snd_hda_codec_resume_amp(codec);
2932 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002933 /* invoke unsolicited event to reset the HP state */
2934 if (spec->hp_detect)
2935 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02002936 return 0;
2937}
2938#endif
2939
Matt2f2f4252005-04-13 14:45:30 +02002940static struct hda_codec_ops stac92xx_patch_ops = {
2941 .build_controls = stac92xx_build_controls,
2942 .build_pcms = stac92xx_build_pcms,
2943 .init = stac92xx_init,
2944 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02002945 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002946#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02002947 .resume = stac92xx_resume,
2948#endif
Matt2f2f4252005-04-13 14:45:30 +02002949};
2950
2951static int patch_stac9200(struct hda_codec *codec)
2952{
2953 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002954 int err;
Matt2f2f4252005-04-13 14:45:30 +02002955
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002956 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02002957 if (spec == NULL)
2958 return -ENOMEM;
2959
2960 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02002961 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02002962 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002963 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
2964 stac9200_models,
2965 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02002966 if (spec->board_config < 0) {
2967 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
2968 err = stac92xx_save_bios_config_regs(codec);
2969 if (err < 0) {
2970 stac92xx_free(codec);
2971 return err;
2972 }
2973 spec->pin_configs = spec->bios_pin_configs;
2974 } else {
Matt Porter403d1942005-11-29 15:00:51 +01002975 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
2976 stac92xx_set_config_regs(codec);
2977 }
Matt2f2f4252005-04-13 14:45:30 +02002978
2979 spec->multiout.max_channels = 2;
2980 spec->multiout.num_dacs = 1;
2981 spec->multiout.dac_nids = stac9200_dac_nids;
2982 spec->adc_nids = stac9200_adc_nids;
2983 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02002984 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02002985 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002986 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002987 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002988
Takashi Iwai1194b5b2007-10-10 10:04:26 +02002989 if (spec->board_config == STAC_9200_GATEWAY)
2990 spec->init = stac9200_eapd_init;
2991 else
2992 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02002993 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02002994
2995 err = stac9200_parse_auto_config(codec);
2996 if (err < 0) {
2997 stac92xx_free(codec);
2998 return err;
2999 }
Matt2f2f4252005-04-13 14:45:30 +02003000
3001 codec->patch_ops = stac92xx_patch_ops;
3002
3003 return 0;
3004}
3005
Tobin Davis8e21c342007-01-08 11:04:17 +01003006static int patch_stac925x(struct hda_codec *codec)
3007{
3008 struct sigmatel_spec *spec;
3009 int err;
3010
3011 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3012 if (spec == NULL)
3013 return -ENOMEM;
3014
3015 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003016 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003017 spec->pin_nids = stac925x_pin_nids;
3018 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3019 stac925x_models,
3020 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003021 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003022 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003023 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3024 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003025 err = stac92xx_save_bios_config_regs(codec);
3026 if (err < 0) {
3027 stac92xx_free(codec);
3028 return err;
3029 }
3030 spec->pin_configs = spec->bios_pin_configs;
3031 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3032 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3033 stac92xx_set_config_regs(codec);
3034 }
3035
3036 spec->multiout.max_channels = 2;
3037 spec->multiout.num_dacs = 1;
3038 spec->multiout.dac_nids = stac925x_dac_nids;
3039 spec->adc_nids = stac925x_adc_nids;
3040 spec->mux_nids = stac925x_mux_nids;
3041 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003042 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003043 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003044 switch (codec->vendor_id) {
3045 case 0x83847632: /* STAC9202 */
3046 case 0x83847633: /* STAC9202D */
3047 case 0x83847636: /* STAC9251 */
3048 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003049 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003050 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003051 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3052 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003053 break;
3054 default:
3055 spec->num_dmics = 0;
3056 break;
3057 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003058
3059 spec->init = stac925x_core_init;
3060 spec->mixer = stac925x_mixer;
3061
3062 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003063 if (!err) {
3064 if (spec->board_config < 0) {
3065 printk(KERN_WARNING "hda_codec: No auto-config is "
3066 "available, default to model=ref\n");
3067 spec->board_config = STAC_925x_REF;
3068 goto again;
3069 }
3070 err = -EINVAL;
3071 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003072 if (err < 0) {
3073 stac92xx_free(codec);
3074 return err;
3075 }
3076
3077 codec->patch_ops = stac92xx_patch_ops;
3078
3079 return 0;
3080}
3081
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003082static struct hda_input_mux stac92hd73xx_dmux = {
3083 .num_items = 4,
3084 .items = {
3085 { "Analog Inputs", 0x0b },
3086 { "CD", 0x08 },
3087 { "Digital Mic 1", 0x09 },
3088 { "Digital Mic 2", 0x0a },
3089 }
3090};
3091
3092static int patch_stac92hd73xx(struct hda_codec *codec)
3093{
3094 struct sigmatel_spec *spec;
3095 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3096 int err = 0;
3097
3098 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3099 if (spec == NULL)
3100 return -ENOMEM;
3101
3102 codec->spec = spec;
3103 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3104 spec->pin_nids = stac92hd73xx_pin_nids;
3105 spec->board_config = snd_hda_check_board_config(codec,
3106 STAC_92HD73XX_MODELS,
3107 stac92hd73xx_models,
3108 stac92hd73xx_cfg_tbl);
3109again:
3110 if (spec->board_config < 0) {
3111 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3112 " STAC92HD73XX, using BIOS defaults\n");
3113 err = stac92xx_save_bios_config_regs(codec);
3114 if (err < 0) {
3115 stac92xx_free(codec);
3116 return err;
3117 }
3118 spec->pin_configs = spec->bios_pin_configs;
3119 } else {
3120 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3121 stac92xx_set_config_regs(codec);
3122 }
3123
3124 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3125 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3126
3127 if (spec->multiout.num_dacs < 0) {
3128 printk(KERN_WARNING "hda_codec: Could not determine "
3129 "number of channels defaulting to DAC count\n");
3130 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3131 }
3132
3133 switch (spec->multiout.num_dacs) {
3134 case 0x3: /* 6 Channel */
3135 spec->mixer = stac92hd73xx_6ch_mixer;
3136 spec->init = stac92hd73xx_6ch_core_init;
3137 break;
3138 case 0x4: /* 8 Channel */
3139 spec->multiout.hp_nid = 0x18;
3140 spec->mixer = stac92hd73xx_8ch_mixer;
3141 spec->init = stac92hd73xx_8ch_core_init;
3142 break;
3143 case 0x5: /* 10 Channel */
3144 spec->multiout.hp_nid = 0x19;
3145 spec->mixer = stac92hd73xx_10ch_mixer;
3146 spec->init = stac92hd73xx_10ch_core_init;
3147 };
3148
3149 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3150 spec->aloopback_mask = 0x01;
3151 spec->aloopback_shift = 8;
3152
3153 spec->mux_nids = stac92hd73xx_mux_nids;
3154 spec->adc_nids = stac92hd73xx_adc_nids;
3155 spec->dmic_nids = stac92hd73xx_dmic_nids;
3156 spec->dmux_nids = stac92hd73xx_dmux_nids;
3157
3158 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3159 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3160 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003161 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003162 spec->dinput_mux = &stac92hd73xx_dmux;
3163 /* GPIO0 High = Enable EAPD */
3164 spec->gpio_mask = spec->gpio_data = 0x000001;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003165
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003166 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3167 spec->pwr_nids = stac92hd73xx_pwr_nids;
3168
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003169 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3170
3171 if (!err) {
3172 if (spec->board_config < 0) {
3173 printk(KERN_WARNING "hda_codec: No auto-config is "
3174 "available, default to model=ref\n");
3175 spec->board_config = STAC_92HD73XX_REF;
3176 goto again;
3177 }
3178 err = -EINVAL;
3179 }
3180
3181 if (err < 0) {
3182 stac92xx_free(codec);
3183 return err;
3184 }
3185
3186 codec->patch_ops = stac92xx_patch_ops;
3187
3188 return 0;
3189}
3190
Matthew Ranostaye035b842007-11-06 11:53:55 +01003191static int patch_stac92hd71bxx(struct hda_codec *codec)
3192{
3193 struct sigmatel_spec *spec;
3194 int err = 0;
3195
3196 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3197 if (spec == NULL)
3198 return -ENOMEM;
3199
3200 codec->spec = spec;
3201 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3202 spec->pin_nids = stac92hd71bxx_pin_nids;
3203 spec->board_config = snd_hda_check_board_config(codec,
3204 STAC_92HD71BXX_MODELS,
3205 stac92hd71bxx_models,
3206 stac92hd71bxx_cfg_tbl);
3207again:
3208 if (spec->board_config < 0) {
3209 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3210 " STAC92HD71BXX, using BIOS defaults\n");
3211 err = stac92xx_save_bios_config_regs(codec);
3212 if (err < 0) {
3213 stac92xx_free(codec);
3214 return err;
3215 }
3216 spec->pin_configs = spec->bios_pin_configs;
3217 } else {
3218 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3219 stac92xx_set_config_regs(codec);
3220 }
3221
Matthew Ranostay541eee82007-12-14 12:08:04 +01003222 switch (codec->vendor_id) {
3223 case 0x111d76b6: /* 4 Port without Analog Mixer */
3224 case 0x111d76b7:
3225 case 0x111d76b4: /* 6 Port without Analog Mixer */
3226 case 0x111d76b5:
3227 spec->mixer = stac92hd71bxx_mixer;
3228 spec->init = stac92hd71bxx_core_init;
3229 break;
3230 default:
3231 spec->mixer = stac92hd71bxx_analog_mixer;
3232 spec->init = stac92hd71bxx_analog_core_init;
3233 }
3234
3235 spec->aloopback_mask = 0x20;
3236 spec->aloopback_shift = 0;
3237
Matthew Ranostaye035b842007-11-06 11:53:55 +01003238 spec->gpio_mask = spec->gpio_data = 0x00000001; /* GPIO0 High = EAPD */
Matthew Ranostaye035b842007-11-06 11:53:55 +01003239
Matthew Ranostaye035b842007-11-06 11:53:55 +01003240 spec->mux_nids = stac92hd71bxx_mux_nids;
3241 spec->adc_nids = stac92hd71bxx_adc_nids;
3242 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003243 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003244
3245 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3246 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3247 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003248 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003249
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003250 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3251 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3252
Matthew Ranostaye035b842007-11-06 11:53:55 +01003253 spec->multiout.num_dacs = 2;
3254 spec->multiout.hp_nid = 0x11;
3255 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3256
3257 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3258 if (!err) {
3259 if (spec->board_config < 0) {
3260 printk(KERN_WARNING "hda_codec: No auto-config is "
3261 "available, default to model=ref\n");
3262 spec->board_config = STAC_92HD71BXX_REF;
3263 goto again;
3264 }
3265 err = -EINVAL;
3266 }
3267
3268 if (err < 0) {
3269 stac92xx_free(codec);
3270 return err;
3271 }
3272
3273 codec->patch_ops = stac92xx_patch_ops;
3274
3275 return 0;
3276};
3277
Matt2f2f4252005-04-13 14:45:30 +02003278static int patch_stac922x(struct hda_codec *codec)
3279{
3280 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003281 int err;
Matt2f2f4252005-04-13 14:45:30 +02003282
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003283 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003284 if (spec == NULL)
3285 return -ENOMEM;
3286
3287 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003288 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003289 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003290 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3291 stac922x_models,
3292 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003293 if (spec->board_config == STAC_INTEL_MAC_V3) {
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003294 spec->gpio_mask = spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003295 /* Intel Macs have all same PCI SSID, so we need to check
3296 * codec SSID to distinguish the exact models
3297 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003298 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003299 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003300
3301 case 0x106b0800:
3302 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003303 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003304 case 0x106b0600:
3305 case 0x106b0700:
3306 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003307 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003308 case 0x106b0e00:
3309 case 0x106b0f00:
3310 case 0x106b1600:
3311 case 0x106b1700:
3312 case 0x106b0200:
3313 case 0x106b1e00:
3314 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003315 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003316 case 0x106b1a00:
3317 case 0x00000100:
3318 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003319 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003320 case 0x106b0a00:
3321 case 0x106b2200:
3322 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003323 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003324 }
3325 }
3326
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003327 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003328 if (spec->board_config < 0) {
3329 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3330 "using BIOS defaults\n");
3331 err = stac92xx_save_bios_config_regs(codec);
3332 if (err < 0) {
3333 stac92xx_free(codec);
3334 return err;
3335 }
3336 spec->pin_configs = spec->bios_pin_configs;
3337 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003338 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3339 stac92xx_set_config_regs(codec);
3340 }
Matt2f2f4252005-04-13 14:45:30 +02003341
Matt2f2f4252005-04-13 14:45:30 +02003342 spec->adc_nids = stac922x_adc_nids;
3343 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003344 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003345 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003346 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003347 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003348
3349 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003350 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003351
3352 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003353
Matt Porter3cc08dc2006-01-23 15:27:49 +01003354 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003355 if (!err) {
3356 if (spec->board_config < 0) {
3357 printk(KERN_WARNING "hda_codec: No auto-config is "
3358 "available, default to model=ref\n");
3359 spec->board_config = STAC_D945_REF;
3360 goto again;
3361 }
3362 err = -EINVAL;
3363 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003364 if (err < 0) {
3365 stac92xx_free(codec);
3366 return err;
3367 }
3368
3369 codec->patch_ops = stac92xx_patch_ops;
3370
Takashi Iwai807a46362007-05-29 19:01:37 +02003371 /* Fix Mux capture level; max to 2 */
3372 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3373 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3374 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3375 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3376 (0 << AC_AMPCAP_MUTE_SHIFT));
3377
Matt Porter3cc08dc2006-01-23 15:27:49 +01003378 return 0;
3379}
3380
3381static int patch_stac927x(struct hda_codec *codec)
3382{
3383 struct sigmatel_spec *spec;
3384 int err;
3385
3386 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3387 if (spec == NULL)
3388 return -ENOMEM;
3389
3390 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003391 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003392 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003393 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3394 stac927x_models,
3395 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003396 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003397 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3398 if (spec->board_config < 0)
3399 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3400 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003401 err = stac92xx_save_bios_config_regs(codec);
3402 if (err < 0) {
3403 stac92xx_free(codec);
3404 return err;
3405 }
3406 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003407 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003408 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3409 stac92xx_set_config_regs(codec);
3410 }
3411
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003412 spec->adc_nids = stac927x_adc_nids;
3413 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3414 spec->mux_nids = stac927x_mux_nids;
3415 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
3416 spec->multiout.dac_nids = spec->dac_nids;
3417
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003418 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003419 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003420 case STAC_D965_5ST:
3421 /* GPIO0 High = Enable EAPD */
3422 spec->gpio_mask = spec->gpio_data = 0x00000001;
3423 spec->num_dmics = 0;
3424
Tobin Davis93ed1502006-09-01 21:03:12 +02003425 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003426 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003427 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003428 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003429 /* correct the front output jack as a hp out */
3430 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003431 /* correct the front input jack as a mic */
3432 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3433 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003434 case STAC_DELL_3ST:
3435 /* GPIO2 High = Enable EAPD */
3436 spec->gpio_mask = spec->gpio_data = 0x00000004;
3437 spec->dmic_nids = stac927x_dmic_nids;
3438 spec->num_dmics = STAC927X_NUM_DMICS;
3439
Tobin Davis93ed1502006-09-01 21:03:12 +02003440 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003441 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003442 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003443 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003444 break;
3445 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003446 /* GPIO0 High = Enable EAPD */
3447 spec->gpio_mask = spec->gpio_data = 0x00000001;
3448 spec->num_dmics = 0;
3449
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003450 spec->init = stac927x_core_init;
3451 spec->mixer = stac927x_mixer;
3452 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003453
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003454 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003455 spec->aloopback_mask = 0x40;
3456 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003457
Matt Porter3cc08dc2006-01-23 15:27:49 +01003458 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003459 if (!err) {
3460 if (spec->board_config < 0) {
3461 printk(KERN_WARNING "hda_codec: No auto-config is "
3462 "available, default to model=ref\n");
3463 spec->board_config = STAC_D965_REF;
3464 goto again;
3465 }
3466 err = -EINVAL;
3467 }
Mattc7d4b2f2005-06-27 14:59:41 +02003468 if (err < 0) {
3469 stac92xx_free(codec);
3470 return err;
3471 }
Matt2f2f4252005-04-13 14:45:30 +02003472
3473 codec->patch_ops = stac92xx_patch_ops;
3474
Takashi Iwai52987652008-01-16 16:09:47 +01003475 /*
3476 * !!FIXME!!
3477 * The STAC927x seem to require fairly long delays for certain
3478 * command sequences. With too short delays (even if the answer
3479 * is set to RIRB properly), it results in the silence output
3480 * on some hardwares like Dell.
3481 *
3482 * The below flag enables the longer delay (see get_response
3483 * in hda_intel.c).
3484 */
3485 codec->bus->needs_damn_long_delay = 1;
3486
Matt2f2f4252005-04-13 14:45:30 +02003487 return 0;
3488}
3489
Matt Porterf3302a52006-07-31 12:49:34 +02003490static int patch_stac9205(struct hda_codec *codec)
3491{
3492 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003493 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003494
3495 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3496 if (spec == NULL)
3497 return -ENOMEM;
3498
3499 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003500 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003501 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003502 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3503 stac9205_models,
3504 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003505 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003506 if (spec->board_config < 0) {
3507 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3508 err = stac92xx_save_bios_config_regs(codec);
3509 if (err < 0) {
3510 stac92xx_free(codec);
3511 return err;
3512 }
3513 spec->pin_configs = spec->bios_pin_configs;
3514 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003515 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3516 stac92xx_set_config_regs(codec);
3517 }
3518
3519 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003520 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003521 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003522 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003523 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003524 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003525 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003526 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003527 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003528
3529 spec->init = stac9205_core_init;
3530 spec->mixer = stac9205_mixer;
3531
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003532 spec->aloopback_mask = 0x40;
3533 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003534 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003535
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003536 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003537 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003538 /* Enable SPDIF in/out */
3539 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3540 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003541
Takashi Iwai82599802007-07-31 15:56:24 +02003542 spec->gpio_mask = 0x00000007; /* GPIO0-2 */
Matthew Ranostay87d48362007-07-17 11:52:24 +02003543 /* GPIO0 High = EAPD, GPIO1 Low = DRM,
3544 * GPIO2 High = Headphone Mute
3545 */
Takashi Iwai82599802007-07-31 15:56:24 +02003546 spec->gpio_data = 0x00000005;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003547 break;
3548 default:
3549 /* GPIO0 High = EAPD */
3550 spec->gpio_mask = spec->gpio_data = 0x00000001;
3551 break;
3552 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003553
Matt Porterf3302a52006-07-31 12:49:34 +02003554 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003555 if (!err) {
3556 if (spec->board_config < 0) {
3557 printk(KERN_WARNING "hda_codec: No auto-config is "
3558 "available, default to model=ref\n");
3559 spec->board_config = STAC_9205_REF;
3560 goto again;
3561 }
3562 err = -EINVAL;
3563 }
Matt Porterf3302a52006-07-31 12:49:34 +02003564 if (err < 0) {
3565 stac92xx_free(codec);
3566 return err;
3567 }
3568
3569 codec->patch_ops = stac92xx_patch_ops;
3570
3571 return 0;
3572}
3573
Matt2f2f4252005-04-13 14:45:30 +02003574/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003575 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003576 */
3577
Guillaume Munch99ccc562006-08-16 19:35:12 +02003578/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003579static hda_nid_t vaio_dacs[] = { 0x2 };
3580#define VAIO_HP_DAC 0x5
3581static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3582static hda_nid_t vaio_mux_nids[] = { 0x15 };
3583
3584static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003585 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003586 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003587 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003588 { "Mic Jack", 0x1 },
3589 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003590 { "PCM", 0x3 },
3591 }
3592};
3593
3594static struct hda_verb vaio_init[] = {
3595 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003596 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003597 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3598 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3599 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3600 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003601 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003602 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3603 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3604 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3605 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3606 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3607 {}
3608};
3609
Guillaume Munch6d859062006-08-22 17:15:47 +02003610static struct hda_verb vaio_ar_init[] = {
3611 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3612 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3613 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3614 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3615/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3616 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003617 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003618 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3619 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3620/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3621 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3623 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3624 {}
3625};
3626
Takashi Iwaidb064e52006-03-16 16:04:58 +01003627/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003628static struct hda_bind_ctls vaio_bind_master_vol = {
3629 .ops = &snd_hda_bind_vol,
3630 .values = {
3631 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3632 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3633 0
3634 },
3635};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003636
3637/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003638static struct hda_bind_ctls vaio_bind_master_sw = {
3639 .ops = &snd_hda_bind_sw,
3640 .values = {
3641 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3642 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3643 0,
3644 },
3645};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003646
3647static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003648 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3649 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003650 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3651 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3652 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3653 {
3654 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3655 .name = "Capture Source",
3656 .count = 1,
3657 .info = stac92xx_mux_enum_info,
3658 .get = stac92xx_mux_enum_get,
3659 .put = stac92xx_mux_enum_put,
3660 },
3661 {}
3662};
3663
Guillaume Munch6d859062006-08-22 17:15:47 +02003664static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003665 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3666 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003667 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3668 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3669 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3670 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3671 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3672 {
3673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3674 .name = "Capture Source",
3675 .count = 1,
3676 .info = stac92xx_mux_enum_info,
3677 .get = stac92xx_mux_enum_get,
3678 .put = stac92xx_mux_enum_put,
3679 },
3680 {}
3681};
3682
3683static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003684 .build_controls = stac92xx_build_controls,
3685 .build_pcms = stac92xx_build_pcms,
3686 .init = stac92xx_init,
3687 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003688#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003689 .resume = stac92xx_resume,
3690#endif
3691};
3692
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003693static int stac9872_vaio_init(struct hda_codec *codec)
3694{
3695 int err;
3696
3697 err = stac92xx_init(codec);
3698 if (err < 0)
3699 return err;
3700 if (codec->patch_ops.unsol_event)
3701 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3702 return 0;
3703}
3704
3705static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3706{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003707 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003708 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3709 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3710 } else {
3711 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3712 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3713 }
3714}
3715
3716static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3717{
3718 switch (res >> 26) {
3719 case STAC_HP_EVENT:
3720 stac9872_vaio_hp_detect(codec, res);
3721 break;
3722 }
3723}
3724
3725static struct hda_codec_ops stac9872_vaio_patch_ops = {
3726 .build_controls = stac92xx_build_controls,
3727 .build_pcms = stac92xx_build_pcms,
3728 .init = stac9872_vaio_init,
3729 .free = stac92xx_free,
3730 .unsol_event = stac9872_vaio_unsol_event,
3731#ifdef CONFIG_PM
3732 .resume = stac92xx_resume,
3733#endif
3734};
3735
Guillaume Munch6d859062006-08-22 17:15:47 +02003736enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3737 CXD9872RD_VAIO,
3738 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3739 STAC9872AK_VAIO,
3740 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3741 STAC9872K_VAIO,
3742 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003743 CXD9872AKD_VAIO,
3744 STAC_9872_MODELS,
3745};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003746
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003747static const char *stac9872_models[STAC_9872_MODELS] = {
3748 [CXD9872RD_VAIO] = "vaio",
3749 [CXD9872AKD_VAIO] = "vaio-ar",
3750};
3751
3752static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3753 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3754 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3755 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003756 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003757 {}
3758};
3759
Guillaume Munch6d859062006-08-22 17:15:47 +02003760static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003761{
3762 struct sigmatel_spec *spec;
3763 int board_config;
3764
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003765 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3766 stac9872_models,
3767 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003768 if (board_config < 0)
3769 /* unknown config, let generic-parser do its job... */
3770 return snd_hda_parse_generic_codec(codec);
3771
3772 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3773 if (spec == NULL)
3774 return -ENOMEM;
3775
3776 codec->spec = spec;
3777 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003778 case CXD9872RD_VAIO:
3779 case STAC9872AK_VAIO:
3780 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003781 spec->mixer = vaio_mixer;
3782 spec->init = vaio_init;
3783 spec->multiout.max_channels = 2;
3784 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3785 spec->multiout.dac_nids = vaio_dacs;
3786 spec->multiout.hp_nid = VAIO_HP_DAC;
3787 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3788 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003789 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003790 spec->input_mux = &vaio_mux;
3791 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003792 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003793 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003794
3795 case CXD9872AKD_VAIO:
3796 spec->mixer = vaio_ar_mixer;
3797 spec->init = vaio_ar_init;
3798 spec->multiout.max_channels = 2;
3799 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3800 spec->multiout.dac_nids = vaio_dacs;
3801 spec->multiout.hp_nid = VAIO_HP_DAC;
3802 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003803 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02003804 spec->adc_nids = vaio_adcs;
3805 spec->input_mux = &vaio_mux;
3806 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003807 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003808 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003809 }
3810
Takashi Iwaidb064e52006-03-16 16:04:58 +01003811 return 0;
3812}
3813
3814
3815/*
Matt2f2f4252005-04-13 14:45:30 +02003816 * patch entries
3817 */
3818struct hda_codec_preset snd_hda_preset_sigmatel[] = {
3819 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
3820 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
3821 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
3822 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
3823 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
3824 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
3825 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02003826 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
3827 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
3828 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
3829 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
3830 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
3831 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01003832 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
3833 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
3834 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
3835 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
3836 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
3837 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
3838 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
3839 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
3840 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
3841 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01003842 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
3843 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
3844 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
3845 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
3846 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
3847 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02003848 /* The following does not take into account .id=0x83847661 when subsys =
3849 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
3850 * currently not fully supported.
3851 */
3852 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
3853 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
3854 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02003855 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
3856 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
3857 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
3858 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
3859 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
3860 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
3861 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
3862 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01003863 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
3864 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003865 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01003866 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
3867 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
3868 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
3869 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
3870 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
3871 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
3872 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
3873 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
3874 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02003875 {} /* terminator */
3876};