blob: f693011d25a00265c791aa0d823b7984ba3cc5ef [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,
Tobin Davisbf277782008-02-03 20:31:47 +010042 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020043 STAC_9200_DELL_D21,
44 STAC_9200_DELL_D22,
45 STAC_9200_DELL_D23,
46 STAC_9200_DELL_M21,
47 STAC_9200_DELL_M22,
48 STAC_9200_DELL_M23,
49 STAC_9200_DELL_M24,
50 STAC_9200_DELL_M25,
51 STAC_9200_DELL_M26,
52 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020053 STAC_9200_GATEWAY,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010054 STAC_9200_MODELS
55};
56
57enum {
58 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020059 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020060 STAC_9205_DELL_M43,
61 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010062 STAC_9205_MODELS
63};
64
65enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010066 STAC_92HD73XX_REF,
67 STAC_92HD73XX_MODELS
68};
69
70enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010071 STAC_92HD71BXX_REF,
72 STAC_92HD71BXX_MODELS
73};
74
75enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010076 STAC_925x_REF,
77 STAC_M2_2,
78 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020079 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010080 STAC_925x_MODELS
81};
82
83enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010084 STAC_D945_REF,
85 STAC_D945GTP3,
86 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020087 STAC_INTEL_MAC_V1,
88 STAC_INTEL_MAC_V2,
89 STAC_INTEL_MAC_V3,
90 STAC_INTEL_MAC_V4,
91 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020092 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010093 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010094 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +010095 STAC_MACBOOK_PRO_V1,
96 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +020097 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +020098 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020099 STAC_922X_DELL_D81,
100 STAC_922X_DELL_D82,
101 STAC_922X_DELL_M81,
102 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100103 STAC_922X_MODELS
104};
105
106enum {
107 STAC_D965_REF,
108 STAC_D965_3ST,
109 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200110 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100111 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100112 STAC_927X_MODELS
113};
Matt Porter403d1942005-11-29 15:00:51 +0100114
Matt2f2f4252005-04-13 14:45:30 +0200115struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100116 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200117 unsigned int num_mixers;
118
Matt Porter403d1942005-11-29 15:00:51 +0100119 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200120 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100121 unsigned int line_switch: 1;
122 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100123 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100124 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200125
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100126 /* gpio lines */
127 unsigned int gpio_mask;
128 unsigned int gpio_dir;
129 unsigned int gpio_data;
130 unsigned int gpio_mute;
131
132 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100133 unsigned char aloopback_mask;
134 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200135
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100136 /* power management */
137 unsigned int num_pwrs;
138 hda_nid_t *pwr_nids;
139
Matt2f2f4252005-04-13 14:45:30 +0200140 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100141 struct hda_input_mux *mono_mux;
142 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200143 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100144 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200145
146 /* capture */
147 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200148 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200149 hda_nid_t *mux_nids;
150 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200151 hda_nid_t *dmic_nids;
152 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100153 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100154 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200155 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100156 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200157
Matt2f2f4252005-04-13 14:45:30 +0200158 /* pin widgets */
159 hda_nid_t *pin_nids;
160 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200161 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200162 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200163
164 /* codec specific stuff */
165 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100166 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200167
168 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200169 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100170 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200171 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100172 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200173
Matt Porter403d1942005-11-29 15:00:51 +0100174 /* i/o switches */
175 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200176 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200177 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200178
Mattc7d4b2f2005-06-27 14:59:41 +0200179 struct hda_pcm pcm_rec[2]; /* PCM information */
180
181 /* dynamic controls and input_mux */
182 struct auto_pin_cfg autocfg;
183 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100184 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200185 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200186 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100187 struct hda_input_mux private_mono_mux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100188
189 /* virtual master */
190 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200191};
192
193static hda_nid_t stac9200_adc_nids[1] = {
194 0x03,
195};
196
197static hda_nid_t stac9200_mux_nids[1] = {
198 0x0c,
199};
200
201static hda_nid_t stac9200_dac_nids[1] = {
202 0x02,
203};
204
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100205static hda_nid_t stac92hd73xx_pwr_nids[8] = {
206 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
207 0x0f, 0x10, 0x11
208};
209
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100210static hda_nid_t stac92hd73xx_adc_nids[2] = {
211 0x1a, 0x1b
212};
213
214#define STAC92HD73XX_NUM_DMICS 2
215static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
216 0x13, 0x14, 0
217};
218
219#define STAC92HD73_DAC_COUNT 5
220static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
221 0x15, 0x16, 0x17, 0x18, 0x19,
222};
223
224static hda_nid_t stac92hd73xx_mux_nids[4] = {
225 0x28, 0x29, 0x2a, 0x2b,
226};
227
228static hda_nid_t stac92hd73xx_dmux_nids[2] = {
229 0x20, 0x21,
230};
231
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100232static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
233 0x0a, 0x0d, 0x0f
234};
235
Matthew Ranostaye035b842007-11-06 11:53:55 +0100236static hda_nid_t stac92hd71bxx_adc_nids[2] = {
237 0x12, 0x13,
238};
239
240static hda_nid_t stac92hd71bxx_mux_nids[2] = {
241 0x1a, 0x1b
242};
243
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100244static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
245 0x1c,
246};
247
Matthew Ranostaye035b842007-11-06 11:53:55 +0100248static hda_nid_t stac92hd71bxx_dac_nids[2] = {
249 0x10, /*0x11, */
250};
251
252#define STAC92HD71BXX_NUM_DMICS 2
253static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
254 0x18, 0x19, 0
255};
256
Tobin Davis8e21c342007-01-08 11:04:17 +0100257static hda_nid_t stac925x_adc_nids[1] = {
258 0x03,
259};
260
261static hda_nid_t stac925x_mux_nids[1] = {
262 0x0f,
263};
264
265static hda_nid_t stac925x_dac_nids[1] = {
266 0x02,
267};
268
Takashi Iwaif6e98522007-10-16 14:27:04 +0200269#define STAC925X_NUM_DMICS 1
270static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
271 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200272};
273
Takashi Iwai1697055e2007-12-18 18:05:52 +0100274static hda_nid_t stac925x_dmux_nids[1] = {
275 0x14,
276};
277
Matt2f2f4252005-04-13 14:45:30 +0200278static hda_nid_t stac922x_adc_nids[2] = {
279 0x06, 0x07,
280};
281
282static hda_nid_t stac922x_mux_nids[2] = {
283 0x12, 0x13,
284};
285
Matt Porter3cc08dc2006-01-23 15:27:49 +0100286static hda_nid_t stac927x_adc_nids[3] = {
287 0x07, 0x08, 0x09
288};
289
290static hda_nid_t stac927x_mux_nids[3] = {
291 0x15, 0x16, 0x17
292};
293
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100294static hda_nid_t stac927x_dmux_nids[1] = {
295 0x1b,
296};
297
Matthew Ranostay7f168592007-10-18 17:38:17 +0200298#define STAC927X_NUM_DMICS 2
299static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
300 0x13, 0x14, 0
301};
302
Matt Porterf3302a52006-07-31 12:49:34 +0200303static hda_nid_t stac9205_adc_nids[2] = {
304 0x12, 0x13
305};
306
307static hda_nid_t stac9205_mux_nids[2] = {
308 0x19, 0x1a
309};
310
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100311static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100312 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100313};
314
Takashi Iwaif6e98522007-10-16 14:27:04 +0200315#define STAC9205_NUM_DMICS 2
316static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
317 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200318};
319
Mattc7d4b2f2005-06-27 14:59:41 +0200320static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200321 0x08, 0x09, 0x0d, 0x0e,
322 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200323};
324
Tobin Davis8e21c342007-01-08 11:04:17 +0100325static hda_nid_t stac925x_pin_nids[8] = {
326 0x07, 0x08, 0x0a, 0x0b,
327 0x0c, 0x0d, 0x10, 0x11,
328};
329
Matt2f2f4252005-04-13 14:45:30 +0200330static hda_nid_t stac922x_pin_nids[10] = {
331 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
332 0x0f, 0x10, 0x11, 0x15, 0x1b,
333};
334
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100335static hda_nid_t stac92hd73xx_pin_nids[12] = {
336 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
337 0x0f, 0x10, 0x11, 0x12, 0x13,
338 0x14, 0x22
339};
340
Matthew Ranostaye035b842007-11-06 11:53:55 +0100341static hda_nid_t stac92hd71bxx_pin_nids[10] = {
342 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
343 0x0f, 0x14, 0x18, 0x19, 0x1e,
344};
345
Matt Porter3cc08dc2006-01-23 15:27:49 +0100346static hda_nid_t stac927x_pin_nids[14] = {
347 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
348 0x0f, 0x10, 0x11, 0x12, 0x13,
349 0x14, 0x21, 0x22, 0x23,
350};
351
Matt Porterf3302a52006-07-31 12:49:34 +0200352static hda_nid_t stac9205_pin_nids[12] = {
353 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
354 0x0f, 0x14, 0x16, 0x17, 0x18,
355 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200356};
357
Matt Porter8b657272006-10-26 17:12:59 +0200358static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_info *uinfo)
360{
361 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
362 struct sigmatel_spec *spec = codec->spec;
363 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
364}
365
366static int stac92xx_dmux_enum_get(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
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100373 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200374 return 0;
375}
376
377static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
378 struct snd_ctl_elem_value *ucontrol)
379{
380 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
381 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100382 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200383
384 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100385 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200386}
387
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100388static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200389{
390 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
391 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200392 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200393}
394
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100395static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200396{
397 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
398 struct sigmatel_spec *spec = codec->spec;
399 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
400
401 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
402 return 0;
403}
404
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100405static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200406{
407 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
408 struct sigmatel_spec *spec = codec->spec;
409 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
410
Mattc7d4b2f2005-06-27 14:59:41 +0200411 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200412 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
413}
414
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100415static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
416 struct snd_ctl_elem_info *uinfo)
417{
418 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
419 struct sigmatel_spec *spec = codec->spec;
420 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
421}
422
423static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
424 struct snd_ctl_elem_value *ucontrol)
425{
426 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
427 struct sigmatel_spec *spec = codec->spec;
428
429 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
430 return 0;
431}
432
433static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
434 struct snd_ctl_elem_value *ucontrol)
435{
436 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
437 struct sigmatel_spec *spec = codec->spec;
438
439 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
440 spec->mono_nid, &spec->cur_mmux);
441}
442
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200443#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
444
445static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
446 struct snd_ctl_elem_value *ucontrol)
447{
448 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100449 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200450 struct sigmatel_spec *spec = codec->spec;
451
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100452 ucontrol->value.integer.value[0] = !!(spec->aloopback &
453 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200454 return 0;
455}
456
457static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
458 struct snd_ctl_elem_value *ucontrol)
459{
460 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
461 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100462 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200463 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100464 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200465
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100466 idx_val = spec->aloopback_mask << idx;
467 if (ucontrol->value.integer.value[0])
468 val = spec->aloopback | idx_val;
469 else
470 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100471 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200472 return 0;
473
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100474 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200475
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100476 /* Only return the bits defined by the shift value of the
477 * first two bytes of the mask
478 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200479 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100480 kcontrol->private_value & 0xFFFF, 0x0);
481 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200482
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100483 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200484 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100485 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200486 } else {
487 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100488 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200489 }
490
491 snd_hda_codec_write_cache(codec, codec->afg, 0,
492 kcontrol->private_value >> 16, dac_mode);
493
494 return 1;
495}
496
Mattc7d4b2f2005-06-27 14:59:41 +0200497static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200498 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200499 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200500 {}
501};
502
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200503static struct hda_verb stac9200_eapd_init[] = {
504 /* set dac0mux for dac converter */
505 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
506 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
507 {}
508};
509
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100510static struct hda_verb stac92hd73xx_6ch_core_init[] = {
511 /* set master volume and direct control */
512 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
513 /* setup audio connections */
514 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
515 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
516 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
517 /* setup adcs to point to mixer */
518 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
519 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100520 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
521 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
522 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
523 /* setup import muxs */
524 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
525 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
526 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
527 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
528 {}
529};
530
531static struct hda_verb stac92hd73xx_8ch_core_init[] = {
532 /* set master volume and direct control */
533 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
534 /* setup audio connections */
535 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
536 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
537 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
538 /* connect hp ports to dac3 */
539 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
540 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
541 /* setup adcs to point to mixer */
542 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
543 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100544 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
545 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
546 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
547 /* setup import muxs */
548 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
549 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
550 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
551 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
552 {}
553};
554
555static struct hda_verb stac92hd73xx_10ch_core_init[] = {
556 /* set master volume and direct control */
557 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
558 /* setup audio connections */
559 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
560 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
561 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
562 /* dac3 is connected to import3 mux */
563 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
564 /* connect hp ports to dac4 */
565 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
566 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
567 /* setup adcs to point to mixer */
568 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
569 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100570 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
571 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
572 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
573 /* setup import muxs */
574 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
575 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
576 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
577 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
578 {}
579};
580
Matthew Ranostaye035b842007-11-06 11:53:55 +0100581static struct hda_verb stac92hd71bxx_core_init[] = {
582 /* set master volume and direct control */
583 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
584 /* connect headphone jack to dac1 */
585 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100586 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
587 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
588 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
589 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
590 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100591};
592
593static struct hda_verb stac92hd71bxx_analog_core_init[] = {
594 /* set master volume and direct control */
595 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
596 /* connect headphone jack to dac1 */
597 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100598 /* connect ports 0d and 0f to audio mixer */
599 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
600 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100601 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100602 /* unmute dac0 input in audio mixer */
603 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100604 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
605 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
606 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
607 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100608 {}
609};
610
Tobin Davis8e21c342007-01-08 11:04:17 +0100611static struct hda_verb stac925x_core_init[] = {
612 /* set dac0mux for dac converter */
613 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
614 {}
615};
616
Mattc7d4b2f2005-06-27 14:59:41 +0200617static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200618 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200619 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200620 {}
621};
622
Tobin Davis93ed1502006-09-01 21:03:12 +0200623static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200624 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200625 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200626 /* unmute node 0x1b */
627 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
628 /* select node 0x03 as DAC */
629 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
630 {}
631};
632
Matt Porter3cc08dc2006-01-23 15:27:49 +0100633static struct hda_verb stac927x_core_init[] = {
634 /* set master volume and direct control */
635 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
636 {}
637};
638
Matt Porterf3302a52006-07-31 12:49:34 +0200639static struct hda_verb stac9205_core_init[] = {
640 /* set master volume and direct control */
641 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
642 {}
643};
644
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100645#define STAC_MONO_MUX \
646 { \
647 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
648 .name = "Mono Mux", \
649 .count = 1, \
650 .info = stac92xx_mono_mux_enum_info, \
651 .get = stac92xx_mono_mux_enum_get, \
652 .put = stac92xx_mono_mux_enum_put, \
653 }
654
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200655#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200656 { \
657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
658 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200659 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200660 .info = stac92xx_mux_enum_info, \
661 .get = stac92xx_mux_enum_get, \
662 .put = stac92xx_mux_enum_put, \
663 }
664
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100665#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200666 { \
667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
668 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100669 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200670 .info = stac92xx_aloopback_info, \
671 .get = stac92xx_aloopback_get, \
672 .put = stac92xx_aloopback_put, \
673 .private_value = verb_read | (verb_write << 16), \
674 }
675
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100676static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200677 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
678 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200679 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200680 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
681 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200682 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200683 { } /* end */
684};
685
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100686static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100687 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
688
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100689 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
690 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
691
692 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
693 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
694
695 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
696 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
697
698 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
699 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
700
701 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
702 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
703
704 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
705 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
706
707 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
708 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
709 { } /* end */
710};
711
712static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100713 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
714
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100715 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
716 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
717
718 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
719 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
720
721 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
722 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
723
724 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
725 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
726
727 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
728 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
729
730 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
731 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
732
733 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
734 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
735 { } /* end */
736};
737
738static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100739 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
740
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100741 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
742 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
743
744 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
745 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
746
747 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
748 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
749
750 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
751 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
752
753 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
754 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
755
756 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
757 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
758
759 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
760 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
761 { } /* end */
762};
763
Matthew Ranostay541eee82007-12-14 12:08:04 +0100764static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100765 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100766
Matthew Ranostay9b359472007-11-07 13:03:12 +0100767 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
768 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
769 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
770
771 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
772 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
773 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
774
775 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
776 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100777 { } /* end */
778};
779
Matthew Ranostay541eee82007-12-14 12:08:04 +0100780static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100781 STAC_INPUT_SOURCE(2),
782 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
783
Matthew Ranostay541eee82007-12-14 12:08:04 +0100784 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
785 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
786 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
787
788 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
789 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
790 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
791 { } /* end */
792};
793
Tobin Davis8e21c342007-01-08 11:04:17 +0100794static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200795 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100796 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
797 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
798 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
799 { } /* end */
800};
801
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100802static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200803 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100804 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200805
806 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
807 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
808 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
809
810 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
811 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
812 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
813
814 { } /* end */
815};
816
817/* This needs to be generated dynamically based on sequence */
818static struct snd_kcontrol_new stac922x_mixer[] = {
819 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200820 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
821 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
822 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
823
824 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
825 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
826 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
827 { } /* end */
828};
829
830
831static struct snd_kcontrol_new stac927x_mixer[] = {
832 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100833 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200834
835 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
836 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
837 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
838
839 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
840 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
841 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
842
843 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
844 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
845 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200846 { } /* end */
847};
848
Takashi Iwai1697055e2007-12-18 18:05:52 +0100849static struct snd_kcontrol_new stac_dmux_mixer = {
850 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
851 .name = "Digital Input Source",
852 /* count set later */
853 .info = stac92xx_dmux_enum_info,
854 .get = stac92xx_dmux_enum_get,
855 .put = stac92xx_dmux_enum_put,
856};
857
Takashi Iwai2134ea42008-01-10 16:53:55 +0100858static const char *slave_vols[] = {
859 "Front Playback Volume",
860 "Surround Playback Volume",
861 "Center Playback Volume",
862 "LFE Playback Volume",
863 "Side Playback Volume",
864 "Headphone Playback Volume",
865 "Headphone Playback Volume",
866 "Speaker Playback Volume",
867 "External Speaker Playback Volume",
868 "Speaker2 Playback Volume",
869 NULL
870};
871
872static const char *slave_sws[] = {
873 "Front Playback Switch",
874 "Surround Playback Switch",
875 "Center Playback Switch",
876 "LFE Playback Switch",
877 "Side Playback Switch",
878 "Headphone Playback Switch",
879 "Headphone Playback Switch",
880 "Speaker Playback Switch",
881 "External Speaker Playback Switch",
882 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100883 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100884 NULL
885};
886
Matt2f2f4252005-04-13 14:45:30 +0200887static int stac92xx_build_controls(struct hda_codec *codec)
888{
889 struct sigmatel_spec *spec = codec->spec;
890 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200891 int i;
Matt2f2f4252005-04-13 14:45:30 +0200892
893 err = snd_hda_add_new_ctls(codec, spec->mixer);
894 if (err < 0)
895 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200896
897 for (i = 0; i < spec->num_mixers; i++) {
898 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
899 if (err < 0)
900 return err;
901 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100902 if (spec->num_dmuxes > 0) {
903 stac_dmux_mixer.count = spec->num_dmuxes;
904 err = snd_ctl_add(codec->bus->card,
905 snd_ctl_new1(&stac_dmux_mixer, codec));
906 if (err < 0)
907 return err;
908 }
Mattc7d4b2f2005-06-27 14:59:41 +0200909
Mattdabbed62005-06-14 10:19:34 +0200910 if (spec->multiout.dig_out_nid) {
911 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
912 if (err < 0)
913 return err;
914 }
915 if (spec->dig_in_nid) {
916 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
917 if (err < 0)
918 return err;
919 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100920
921 /* if we have no master control, let's create it */
922 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
923 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
924 HDA_OUTPUT, spec->vmaster_tlv);
925 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
926 spec->vmaster_tlv, slave_vols);
927 if (err < 0)
928 return err;
929 }
930 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
931 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
932 NULL, slave_sws);
933 if (err < 0)
934 return err;
935 }
936
Mattdabbed62005-06-14 10:19:34 +0200937 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200938}
939
Matt Porter403d1942005-11-29 15:00:51 +0100940static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200941 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200942 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
943};
944
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200945/*
946 STAC 9200 pin configs for
947 102801A8
948 102801DE
949 102801E8
950*/
951static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200952 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
953 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200954};
955
956/*
957 STAC 9200 pin configs for
958 102801C0
959 102801C1
960*/
961static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200962 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
963 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200964};
965
966/*
967 STAC 9200 pin configs for
968 102801C4 (Dell Dimension E310)
969 102801C5
970 102801C7
971 102801D9
972 102801DA
973 102801E3
974*/
975static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200976 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
977 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200978};
979
980
981/*
982 STAC 9200-32 pin configs for
983 102801B5 (Dell Inspiron 630m)
984 102801D8 (Dell Inspiron 640m)
985*/
986static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200987 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
988 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200989};
990
991/*
992 STAC 9200-32 pin configs for
993 102801C2 (Dell Latitude D620)
994 102801C8
995 102801CC (Dell Latitude D820)
996 102801D4
997 102801D6
998*/
999static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001000 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1001 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001002};
1003
1004/*
1005 STAC 9200-32 pin configs for
1006 102801CE (Dell XPS M1710)
1007 102801CF (Dell Precision M90)
1008*/
1009static unsigned int dell9200_m23_pin_configs[8] = {
1010 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1011 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1012};
1013
1014/*
1015 STAC 9200-32 pin configs for
1016 102801C9
1017 102801CA
1018 102801CB (Dell Latitude 120L)
1019 102801D3
1020*/
1021static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001022 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1023 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001024};
1025
1026/*
1027 STAC 9200-32 pin configs for
1028 102801BD (Dell Inspiron E1505n)
1029 102801EE
1030 102801EF
1031*/
1032static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001033 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1034 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001035};
1036
1037/*
1038 STAC 9200-32 pin configs for
1039 102801F5 (Dell Inspiron 1501)
1040 102801F6
1041*/
1042static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001043 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1044 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001045};
1046
1047/*
1048 STAC 9200-32
1049 102801CD (Dell Inspiron E1705/9400)
1050*/
1051static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001052 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1053 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001054};
1055
Tobin Davisbf277782008-02-03 20:31:47 +01001056static unsigned int oqo9200_pin_configs[8] = {
1057 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1058 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1059};
1060
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001061
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001062static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1063 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001064 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001065 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1066 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1067 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1068 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1069 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1070 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1071 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1072 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1073 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1074 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001075};
1076
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001077static const char *stac9200_models[STAC_9200_MODELS] = {
1078 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001079 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001080 [STAC_9200_DELL_D21] = "dell-d21",
1081 [STAC_9200_DELL_D22] = "dell-d22",
1082 [STAC_9200_DELL_D23] = "dell-d23",
1083 [STAC_9200_DELL_M21] = "dell-m21",
1084 [STAC_9200_DELL_M22] = "dell-m22",
1085 [STAC_9200_DELL_M23] = "dell-m23",
1086 [STAC_9200_DELL_M24] = "dell-m24",
1087 [STAC_9200_DELL_M25] = "dell-m25",
1088 [STAC_9200_DELL_M26] = "dell-m26",
1089 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001090 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001091};
1092
1093static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1094 /* SigmaTel reference board */
1095 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1096 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001097 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001098 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1099 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001100 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001101 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1102 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1103 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1104 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1105 "unknown Dell", STAC_9200_DELL_D22),
1106 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1107 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001108 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001109 "Dell Latitude D620", STAC_9200_DELL_M22),
1110 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1111 "unknown Dell", STAC_9200_DELL_D23),
1112 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1113 "unknown Dell", STAC_9200_DELL_D23),
1114 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1115 "unknown Dell", STAC_9200_DELL_M22),
1116 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1117 "unknown Dell", STAC_9200_DELL_M24),
1118 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1119 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001120 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001121 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001122 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001123 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001124 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001125 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001126 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001127 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001128 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001129 "Dell Precision M90", STAC_9200_DELL_M23),
1130 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1131 "unknown Dell", STAC_9200_DELL_M22),
1132 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1133 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001134 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001135 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001137 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1139 "unknown Dell", STAC_9200_DELL_D23),
1140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1141 "unknown Dell", STAC_9200_DELL_D23),
1142 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1143 "unknown Dell", STAC_9200_DELL_D21),
1144 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1145 "unknown Dell", STAC_9200_DELL_D23),
1146 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1147 "unknown Dell", STAC_9200_DELL_D21),
1148 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1149 "unknown Dell", STAC_9200_DELL_M25),
1150 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1151 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001153 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1154 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1155 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001156 /* Panasonic */
1157 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001158 /* Gateway machines needs EAPD to be set on resume */
1159 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1160 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1161 STAC_9200_GATEWAY),
1162 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1163 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001164 /* OQO Mobile */
1165 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001166 {} /* terminator */
1167};
1168
Tobin Davis8e21c342007-01-08 11:04:17 +01001169static unsigned int ref925x_pin_configs[8] = {
1170 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001171 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001172};
1173
1174static unsigned int stac925x_MA6_pin_configs[8] = {
1175 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1176 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1177};
1178
Tobin Davis2c11f952007-05-17 09:36:34 +02001179static unsigned int stac925x_PA6_pin_configs[8] = {
1180 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1181 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1182};
1183
Tobin Davis8e21c342007-01-08 11:04:17 +01001184static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001185 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1186 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001187};
1188
1189static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1190 [STAC_REF] = ref925x_pin_configs,
1191 [STAC_M2_2] = stac925xM2_2_pin_configs,
1192 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001193 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001194};
1195
1196static const char *stac925x_models[STAC_925x_MODELS] = {
1197 [STAC_REF] = "ref",
1198 [STAC_M2_2] = "m2-2",
1199 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001200 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001201};
1202
1203static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1204 /* SigmaTel reference board */
1205 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001206 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001207 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1208 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1209 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001210 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001211 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1212 {} /* terminator */
1213};
1214
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001215static unsigned int ref92hd73xx_pin_configs[12] = {
1216 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1217 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1218 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1219};
1220
1221static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1222 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1223};
1224
1225static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1226 [STAC_92HD73XX_REF] = "ref",
1227};
1228
1229static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1230 /* SigmaTel reference board */
1231 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1232 "DFI LanParty", STAC_92HD73XX_REF),
1233 {} /* terminator */
1234};
1235
Matthew Ranostaye035b842007-11-06 11:53:55 +01001236static unsigned int ref92hd71bxx_pin_configs[10] = {
1237 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001238 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001239 0x90a000f0, 0x01452050,
1240};
1241
1242static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1243 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1244};
1245
1246static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1247 [STAC_92HD71BXX_REF] = "ref",
1248};
1249
1250static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1251 /* SigmaTel reference board */
1252 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1253 "DFI LanParty", STAC_92HD71BXX_REF),
1254 {} /* terminator */
1255};
1256
Matt Porter403d1942005-11-29 15:00:51 +01001257static unsigned int ref922x_pin_configs[10] = {
1258 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1259 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001260 0x40000100, 0x40000100,
1261};
1262
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001263/*
1264 STAC 922X pin configs for
1265 102801A7
1266 102801AB
1267 102801A9
1268 102801D1
1269 102801D2
1270*/
1271static unsigned int dell_922x_d81_pin_configs[10] = {
1272 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1273 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1274 0x01813122, 0x400001f2,
1275};
1276
1277/*
1278 STAC 922X pin configs for
1279 102801AC
1280 102801D0
1281*/
1282static unsigned int dell_922x_d82_pin_configs[10] = {
1283 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1284 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1285 0x01813122, 0x400001f1,
1286};
1287
1288/*
1289 STAC 922X pin configs for
1290 102801BF
1291*/
1292static unsigned int dell_922x_m81_pin_configs[10] = {
1293 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1294 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1295 0x40C003f1, 0x405003f0,
1296};
1297
1298/*
1299 STAC 9221 A1 pin configs for
1300 102801D7 (Dell XPS M1210)
1301*/
1302static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001303 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1304 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001305 0x508003f3, 0x405003f4,
1306};
1307
Matt Porter403d1942005-11-29 15:00:51 +01001308static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001309 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001310 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1311 0x02a19120, 0x40000100,
1312};
1313
1314static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001315 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1316 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001317 0x02a19320, 0x40000100,
1318};
1319
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001320static unsigned int intel_mac_v1_pin_configs[10] = {
1321 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1322 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001323 0x400000fc, 0x400000fb,
1324};
1325
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001326static unsigned int intel_mac_v2_pin_configs[10] = {
1327 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1328 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001329 0x400000fc, 0x400000fb,
1330};
1331
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001332static unsigned int intel_mac_v3_pin_configs[10] = {
1333 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1334 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1335 0x400000fc, 0x400000fb,
1336};
1337
1338static unsigned int intel_mac_v4_pin_configs[10] = {
1339 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1340 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1341 0x400000fc, 0x400000fb,
1342};
1343
1344static unsigned int intel_mac_v5_pin_configs[10] = {
1345 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1346 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1347 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001348};
1349
Takashi Iwai76c08822007-06-19 12:17:42 +02001350
Takashi Iwai19039bd2006-06-28 15:52:16 +02001351static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001352 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001353 [STAC_D945GTP3] = d945gtp3_pin_configs,
1354 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001355 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1356 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1357 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1358 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1359 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001360 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001361 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1362 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1363 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1364 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1365 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1366 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001367 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1368 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1369 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1370 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001371};
1372
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001373static const char *stac922x_models[STAC_922X_MODELS] = {
1374 [STAC_D945_REF] = "ref",
1375 [STAC_D945GTP5] = "5stack",
1376 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001377 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1378 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1379 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1380 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1381 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001382 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001383 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001384 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001385 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1386 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001387 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001388 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001389 [STAC_922X_DELL_D81] = "dell-d81",
1390 [STAC_922X_DELL_D82] = "dell-d82",
1391 [STAC_922X_DELL_M81] = "dell-m81",
1392 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001393};
1394
1395static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1396 /* SigmaTel reference board */
1397 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1398 "DFI LanParty", STAC_D945_REF),
1399 /* Intel 945G based systems */
1400 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1401 "Intel D945G", STAC_D945GTP3),
1402 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1403 "Intel D945G", STAC_D945GTP3),
1404 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1405 "Intel D945G", STAC_D945GTP3),
1406 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1407 "Intel D945G", STAC_D945GTP3),
1408 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1409 "Intel D945G", STAC_D945GTP3),
1410 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1411 "Intel D945G", STAC_D945GTP3),
1412 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1413 "Intel D945G", STAC_D945GTP3),
1414 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1415 "Intel D945G", STAC_D945GTP3),
1416 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1417 "Intel D945G", STAC_D945GTP3),
1418 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1419 "Intel D945G", STAC_D945GTP3),
1420 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1421 "Intel D945G", STAC_D945GTP3),
1422 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1423 "Intel D945G", STAC_D945GTP3),
1424 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1425 "Intel D945G", STAC_D945GTP3),
1426 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1427 "Intel D945G", STAC_D945GTP3),
1428 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1429 "Intel D945G", STAC_D945GTP3),
1430 /* Intel D945G 5-stack systems */
1431 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1432 "Intel D945G", STAC_D945GTP5),
1433 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1434 "Intel D945G", STAC_D945GTP5),
1435 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1436 "Intel D945G", STAC_D945GTP5),
1437 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1438 "Intel D945G", STAC_D945GTP5),
1439 /* Intel 945P based systems */
1440 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1441 "Intel D945P", STAC_D945GTP3),
1442 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1443 "Intel D945P", STAC_D945GTP3),
1444 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1445 "Intel D945P", STAC_D945GTP3),
1446 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1447 "Intel D945P", STAC_D945GTP3),
1448 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1449 "Intel D945P", STAC_D945GTP3),
1450 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1451 "Intel D945P", STAC_D945GTP5),
1452 /* other systems */
1453 /* Apple Mac Mini (early 2006) */
1454 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001455 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001456 /* Dell systems */
1457 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1458 "unknown Dell", STAC_922X_DELL_D81),
1459 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1460 "unknown Dell", STAC_922X_DELL_D81),
1461 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1462 "unknown Dell", STAC_922X_DELL_D81),
1463 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1464 "unknown Dell", STAC_922X_DELL_D82),
1465 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1466 "unknown Dell", STAC_922X_DELL_M81),
1467 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1468 "unknown Dell", STAC_922X_DELL_D82),
1469 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1470 "unknown Dell", STAC_922X_DELL_D81),
1471 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1472 "unknown Dell", STAC_922X_DELL_D81),
1473 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1474 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001475 {} /* terminator */
1476};
1477
Matt Porter3cc08dc2006-01-23 15:27:49 +01001478static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001479 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1480 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1481 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1482 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001483};
1484
Tobin Davis93ed1502006-09-01 21:03:12 +02001485static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001486 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1487 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1488 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1489 0x40000100, 0x40000100
1490};
1491
Tobin Davis93ed1502006-09-01 21:03:12 +02001492static unsigned int d965_5st_pin_configs[14] = {
1493 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1494 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1495 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1496 0x40000100, 0x40000100
1497};
1498
Tobin Davis4ff076e2007-08-07 11:48:12 +02001499static unsigned int dell_3st_pin_configs[14] = {
1500 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1501 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001502 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001503 0x40c003fc, 0x40000100
1504};
1505
Tobin Davis93ed1502006-09-01 21:03:12 +02001506static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001507 [STAC_D965_REF] = ref927x_pin_configs,
1508 [STAC_D965_3ST] = d965_3st_pin_configs,
1509 [STAC_D965_5ST] = d965_5st_pin_configs,
1510 [STAC_DELL_3ST] = dell_3st_pin_configs,
1511 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001512};
1513
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001514static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001515 [STAC_D965_REF] = "ref",
1516 [STAC_D965_3ST] = "3stack",
1517 [STAC_D965_5ST] = "5stack",
1518 [STAC_DELL_3ST] = "dell-3stack",
1519 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001520};
1521
1522static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1523 /* SigmaTel reference board */
1524 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1525 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001526 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001529 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001530 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001546 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001547 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001548 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001549 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001551 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001552 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001554 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001560 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001561 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1563 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1564 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1565 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1566 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1567 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1569 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001570 {} /* terminator */
1571};
1572
Matt Porterf3302a52006-07-31 12:49:34 +02001573static unsigned int ref9205_pin_configs[12] = {
1574 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001575 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001576 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001577};
1578
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001579/*
1580 STAC 9205 pin configs for
1581 102801F1
1582 102801F2
1583 102801FC
1584 102801FD
1585 10280204
1586 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001587 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001588*/
1589static unsigned int dell_9205_m42_pin_configs[12] = {
1590 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1591 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1592 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1593};
1594
1595/*
1596 STAC 9205 pin configs for
1597 102801F9
1598 102801FA
1599 102801FE
1600 102801FF (Dell Precision M4300)
1601 10280206
1602 10280200
1603 10280201
1604*/
1605static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001606 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1607 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1608 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1609};
1610
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001611static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001612 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1613 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1614 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1615};
1616
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001617static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001618 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001619 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1620 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1621 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001622};
1623
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001624static const char *stac9205_models[STAC_9205_MODELS] = {
1625 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001626 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001627 [STAC_9205_DELL_M43] = "dell-m43",
1628 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001629};
1630
1631static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1632 /* SigmaTel reference board */
1633 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1634 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001635 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1636 "unknown Dell", STAC_9205_DELL_M42),
1637 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1638 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001639 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001640 "Dell Precision", STAC_9205_DELL_M43),
1641 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1642 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001643 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1644 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1646 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1648 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001649 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1650 "unknown Dell", STAC_9205_DELL_M42),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1652 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001653 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1654 "Dell Precision", STAC_9205_DELL_M43),
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001656 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001657 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1658 "Dell Precision", STAC_9205_DELL_M43),
1659 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1660 "Dell Inspiron", STAC_9205_DELL_M44),
1661 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1662 "Dell Inspiron", STAC_9205_DELL_M44),
1663 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1664 "Dell Inspiron", STAC_9205_DELL_M44),
1665 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1666 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001667 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1668 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001669 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1670 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001671 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1672 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001673 {} /* terminator */
1674};
1675
Richard Fish11b44bb2006-08-23 18:31:34 +02001676static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1677{
1678 int i;
1679 struct sigmatel_spec *spec = codec->spec;
1680
1681 if (! spec->bios_pin_configs) {
1682 spec->bios_pin_configs = kcalloc(spec->num_pins,
1683 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1684 if (! spec->bios_pin_configs)
1685 return -ENOMEM;
1686 }
1687
1688 for (i = 0; i < spec->num_pins; i++) {
1689 hda_nid_t nid = spec->pin_nids[i];
1690 unsigned int pin_cfg;
1691
1692 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1693 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1694 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1695 nid, pin_cfg);
1696 spec->bios_pin_configs[i] = pin_cfg;
1697 }
1698
1699 return 0;
1700}
1701
Matthew Ranostay87d48362007-07-17 11:52:24 +02001702static void stac92xx_set_config_reg(struct hda_codec *codec,
1703 hda_nid_t pin_nid, unsigned int pin_config)
1704{
1705 int i;
1706 snd_hda_codec_write(codec, pin_nid, 0,
1707 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1708 pin_config & 0x000000ff);
1709 snd_hda_codec_write(codec, pin_nid, 0,
1710 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1711 (pin_config & 0x0000ff00) >> 8);
1712 snd_hda_codec_write(codec, pin_nid, 0,
1713 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1714 (pin_config & 0x00ff0000) >> 16);
1715 snd_hda_codec_write(codec, pin_nid, 0,
1716 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1717 pin_config >> 24);
1718 i = snd_hda_codec_read(codec, pin_nid, 0,
1719 AC_VERB_GET_CONFIG_DEFAULT,
1720 0x00);
1721 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1722 pin_nid, i);
1723}
1724
Matt2f2f4252005-04-13 14:45:30 +02001725static void stac92xx_set_config_regs(struct hda_codec *codec)
1726{
1727 int i;
1728 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001729
Matthew Ranostay87d48362007-07-17 11:52:24 +02001730 if (!spec->pin_configs)
1731 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001732
Matthew Ranostay87d48362007-07-17 11:52:24 +02001733 for (i = 0; i < spec->num_pins; i++)
1734 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1735 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001736}
Matt2f2f4252005-04-13 14:45:30 +02001737
Matt2f2f4252005-04-13 14:45:30 +02001738/*
1739 * Analog playback callbacks
1740 */
1741static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1742 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001743 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001744{
1745 struct sigmatel_spec *spec = codec->spec;
1746 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1747}
1748
1749static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1750 struct hda_codec *codec,
1751 unsigned int stream_tag,
1752 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001753 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001754{
1755 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001756 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001757}
1758
1759static int stac92xx_playback_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 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1765}
1766
1767/*
Mattdabbed62005-06-14 10:19:34 +02001768 * Digital playback callbacks
1769 */
1770static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1771 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001772 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001773{
1774 struct sigmatel_spec *spec = codec->spec;
1775 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1776}
1777
1778static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1779 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001780 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001781{
1782 struct sigmatel_spec *spec = codec->spec;
1783 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1784}
1785
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001786static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1787 struct hda_codec *codec,
1788 unsigned int stream_tag,
1789 unsigned int format,
1790 struct snd_pcm_substream *substream)
1791{
1792 struct sigmatel_spec *spec = codec->spec;
1793 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1794 stream_tag, format, substream);
1795}
1796
Mattdabbed62005-06-14 10:19:34 +02001797
1798/*
Matt2f2f4252005-04-13 14:45:30 +02001799 * Analog capture callbacks
1800 */
1801static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1802 struct hda_codec *codec,
1803 unsigned int stream_tag,
1804 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001805 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001806{
1807 struct sigmatel_spec *spec = codec->spec;
1808
1809 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1810 stream_tag, 0, format);
1811 return 0;
1812}
1813
1814static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1815 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001816 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001817{
1818 struct sigmatel_spec *spec = codec->spec;
1819
1820 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1821 return 0;
1822}
1823
Mattdabbed62005-06-14 10:19:34 +02001824static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1825 .substreams = 1,
1826 .channels_min = 2,
1827 .channels_max = 2,
1828 /* NID is set in stac92xx_build_pcms */
1829 .ops = {
1830 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001831 .close = stac92xx_dig_playback_pcm_close,
1832 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001833 },
1834};
1835
1836static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1837 .substreams = 1,
1838 .channels_min = 2,
1839 .channels_max = 2,
1840 /* NID is set in stac92xx_build_pcms */
1841};
1842
Matt2f2f4252005-04-13 14:45:30 +02001843static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1844 .substreams = 1,
1845 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001846 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001847 .nid = 0x02, /* NID to query formats and rates */
1848 .ops = {
1849 .open = stac92xx_playback_pcm_open,
1850 .prepare = stac92xx_playback_pcm_prepare,
1851 .cleanup = stac92xx_playback_pcm_cleanup
1852 },
1853};
1854
Matt Porter3cc08dc2006-01-23 15:27:49 +01001855static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1856 .substreams = 1,
1857 .channels_min = 2,
1858 .channels_max = 2,
1859 .nid = 0x06, /* NID to query formats and rates */
1860 .ops = {
1861 .open = stac92xx_playback_pcm_open,
1862 .prepare = stac92xx_playback_pcm_prepare,
1863 .cleanup = stac92xx_playback_pcm_cleanup
1864 },
1865};
1866
Matt2f2f4252005-04-13 14:45:30 +02001867static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001868 .channels_min = 2,
1869 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001870 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001871 .ops = {
1872 .prepare = stac92xx_capture_pcm_prepare,
1873 .cleanup = stac92xx_capture_pcm_cleanup
1874 },
1875};
1876
1877static int stac92xx_build_pcms(struct hda_codec *codec)
1878{
1879 struct sigmatel_spec *spec = codec->spec;
1880 struct hda_pcm *info = spec->pcm_rec;
1881
1882 codec->num_pcms = 1;
1883 codec->pcm_info = info;
1884
Mattc7d4b2f2005-06-27 14:59:41 +02001885 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001886 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001887 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001888 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001889 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001890
1891 if (spec->alt_switch) {
1892 codec->num_pcms++;
1893 info++;
1894 info->name = "STAC92xx Analog Alt";
1895 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1896 }
Matt2f2f4252005-04-13 14:45:30 +02001897
Mattdabbed62005-06-14 10:19:34 +02001898 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1899 codec->num_pcms++;
1900 info++;
1901 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001902 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02001903 if (spec->multiout.dig_out_nid) {
1904 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1905 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1906 }
1907 if (spec->dig_in_nid) {
1908 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1909 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1910 }
1911 }
1912
Matt2f2f4252005-04-13 14:45:30 +02001913 return 0;
1914}
1915
Takashi Iwaic960a032006-03-23 17:06:28 +01001916static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1917{
1918 unsigned int pincap = snd_hda_param_read(codec, nid,
1919 AC_PAR_PIN_CAP);
1920 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1921 if (pincap & AC_PINCAP_VREF_100)
1922 return AC_PINCTL_VREF_100;
1923 if (pincap & AC_PINCAP_VREF_80)
1924 return AC_PINCTL_VREF_80;
1925 if (pincap & AC_PINCAP_VREF_50)
1926 return AC_PINCTL_VREF_50;
1927 if (pincap & AC_PINCAP_VREF_GRD)
1928 return AC_PINCTL_VREF_GRD;
1929 return 0;
1930}
1931
Matt Porter403d1942005-11-29 15:00:51 +01001932static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1933
1934{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001935 snd_hda_codec_write_cache(codec, nid, 0,
1936 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001937}
1938
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001939#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001940
1941static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1942{
1943 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1944 struct sigmatel_spec *spec = codec->spec;
1945 int io_idx = kcontrol-> private_value & 0xff;
1946
1947 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1948 return 0;
1949}
1950
1951static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1952{
1953 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1954 struct sigmatel_spec *spec = codec->spec;
1955 hda_nid_t nid = kcontrol->private_value >> 8;
1956 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001957 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001958
1959 spec->io_switch[io_idx] = val;
1960
1961 if (val)
1962 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001963 else {
1964 unsigned int pinctl = AC_PINCTL_IN_EN;
1965 if (io_idx) /* set VREF for mic */
1966 pinctl |= stac92xx_get_vref(codec, nid);
1967 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1968 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001969
1970 /* check the auto-mute again: we need to mute/unmute the speaker
1971 * appropriately according to the pin direction
1972 */
1973 if (spec->hp_detect)
1974 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1975
Matt Porter403d1942005-11-29 15:00:51 +01001976 return 1;
1977}
1978
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001979#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1980
1981static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1982 struct snd_ctl_elem_value *ucontrol)
1983{
1984 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1985 struct sigmatel_spec *spec = codec->spec;
1986
1987 ucontrol->value.integer.value[0] = spec->clfe_swap;
1988 return 0;
1989}
1990
1991static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1992 struct snd_ctl_elem_value *ucontrol)
1993{
1994 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1995 struct sigmatel_spec *spec = codec->spec;
1996 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001997 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001998
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001999 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002000 return 0;
2001
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002002 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002003
2004 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2005 spec->clfe_swap ? 0x4 : 0x0);
2006
2007 return 1;
2008}
2009
Matt Porter403d1942005-11-29 15:00:51 +01002010#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2011 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2012 .name = xname, \
2013 .index = 0, \
2014 .info = stac92xx_io_switch_info, \
2015 .get = stac92xx_io_switch_get, \
2016 .put = stac92xx_io_switch_put, \
2017 .private_value = xpval, \
2018 }
2019
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002020#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2021 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2022 .name = xname, \
2023 .index = 0, \
2024 .info = stac92xx_clfe_switch_info, \
2025 .get = stac92xx_clfe_switch_get, \
2026 .put = stac92xx_clfe_switch_put, \
2027 .private_value = xpval, \
2028 }
Matt Porter403d1942005-11-29 15:00:51 +01002029
Mattc7d4b2f2005-06-27 14:59:41 +02002030enum {
2031 STAC_CTL_WIDGET_VOL,
2032 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002033 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002034 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002035 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002036};
2037
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002038static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002039 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2040 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002041 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002042 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002043 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002044};
2045
2046/* add dynamic controls */
2047static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2048{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002049 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002050
2051 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2052 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2053
2054 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2055 if (! knew)
2056 return -ENOMEM;
2057 if (spec->kctl_alloc) {
2058 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2059 kfree(spec->kctl_alloc);
2060 }
2061 spec->kctl_alloc = knew;
2062 spec->num_kctl_alloc = num;
2063 }
2064
2065 knew = &spec->kctl_alloc[spec->num_kctl_used];
2066 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002067 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002068 if (! knew->name)
2069 return -ENOMEM;
2070 knew->private_value = val;
2071 spec->num_kctl_used++;
2072 return 0;
2073}
2074
Matt Porter403d1942005-11-29 15:00:51 +01002075/* flag inputs as additional dynamic lineouts */
2076static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2077{
2078 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002079 unsigned int wcaps, wtype;
2080 int i, num_dacs = 0;
2081
2082 /* use the wcaps cache to count all DACs available for line-outs */
2083 for (i = 0; i < codec->num_nodes; i++) {
2084 wcaps = codec->wcaps[i];
2085 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002086
Steve Longerbeam7b043892007-05-03 20:50:03 +02002087 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2088 num_dacs++;
2089 }
Matt Porter403d1942005-11-29 15:00:51 +01002090
Steve Longerbeam7b043892007-05-03 20:50:03 +02002091 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2092
Matt Porter403d1942005-11-29 15:00:51 +01002093 switch (cfg->line_outs) {
2094 case 3:
2095 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002096 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002097 cfg->line_out_pins[cfg->line_outs] =
2098 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002099 spec->line_switch = 1;
2100 cfg->line_outs++;
2101 }
2102 break;
2103 case 2:
2104 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002105 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002106 cfg->line_out_pins[cfg->line_outs] =
2107 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002108 spec->line_switch = 1;
2109 cfg->line_outs++;
2110 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002111 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002112 cfg->line_out_pins[cfg->line_outs] =
2113 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002114 spec->mic_switch = 1;
2115 cfg->line_outs++;
2116 }
2117 break;
2118 case 1:
2119 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002120 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002121 cfg->line_out_pins[cfg->line_outs] =
2122 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002123 spec->line_switch = 1;
2124 cfg->line_outs++;
2125 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002126 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002127 cfg->line_out_pins[cfg->line_outs] =
2128 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002129 spec->mic_switch = 1;
2130 cfg->line_outs++;
2131 }
2132 break;
2133 }
2134
2135 return 0;
2136}
2137
Steve Longerbeam7b043892007-05-03 20:50:03 +02002138
2139static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2140{
2141 int i;
2142
2143 for (i = 0; i < spec->multiout.num_dacs; i++) {
2144 if (spec->multiout.dac_nids[i] == nid)
2145 return 1;
2146 }
2147
2148 return 0;
2149}
2150
Matt Porter3cc08dc2006-01-23 15:27:49 +01002151/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002152 * Fill in the dac_nids table from the parsed pin configuration
2153 * This function only works when every pin in line_out_pins[]
2154 * contains atleast one DAC in its connection list. Some 92xx
2155 * codecs are not connected directly to a DAC, such as the 9200
2156 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002157 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002158static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002159 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002160{
2161 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002162 int i, j, conn_len = 0;
2163 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2164 unsigned int wcaps, wtype;
2165
Mattc7d4b2f2005-06-27 14:59:41 +02002166 for (i = 0; i < cfg->line_outs; i++) {
2167 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002168 conn_len = snd_hda_get_connections(codec, nid, conn,
2169 HDA_MAX_CONNECTIONS);
2170 for (j = 0; j < conn_len; j++) {
2171 wcaps = snd_hda_param_read(codec, conn[j],
2172 AC_PAR_AUDIO_WIDGET_CAP);
2173 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002174 if (wtype != AC_WID_AUD_OUT ||
2175 (wcaps & AC_WCAP_DIGITAL))
2176 continue;
2177 /* conn[j] is a DAC routed to this line-out */
2178 if (!is_in_dac_nids(spec, conn[j]))
2179 break;
2180 }
2181
2182 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002183 if (spec->multiout.num_dacs > 0) {
2184 /* we have already working output pins,
2185 * so let's drop the broken ones again
2186 */
2187 cfg->line_outs = spec->multiout.num_dacs;
2188 break;
2189 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002190 /* error out, no available DAC found */
2191 snd_printk(KERN_ERR
2192 "%s: No available DAC for pin 0x%x\n",
2193 __func__, nid);
2194 return -ENODEV;
2195 }
2196
2197 spec->multiout.dac_nids[i] = conn[j];
2198 spec->multiout.num_dacs++;
2199 if (conn_len > 1) {
2200 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002201 snd_hda_codec_write_cache(codec, nid, 0,
2202 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002203
2204 }
Mattc7d4b2f2005-06-27 14:59:41 +02002205 }
2206
Steve Longerbeam7b043892007-05-03 20:50:03 +02002207 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2208 spec->multiout.num_dacs,
2209 spec->multiout.dac_nids[0],
2210 spec->multiout.dac_nids[1],
2211 spec->multiout.dac_nids[2],
2212 spec->multiout.dac_nids[3],
2213 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002214 return 0;
2215}
2216
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002217/* create volume control/switch for the given prefx type */
2218static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2219{
2220 char name[32];
2221 int err;
2222
2223 sprintf(name, "%s Playback Volume", pfx);
2224 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2225 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2226 if (err < 0)
2227 return err;
2228 sprintf(name, "%s Playback Switch", pfx);
2229 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2230 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2231 if (err < 0)
2232 return err;
2233 return 0;
2234}
2235
Mattc7d4b2f2005-06-27 14:59:41 +02002236/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002237static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002238 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002239{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002240 static const char *chname[4] = {
2241 "Front", "Surround", NULL /*CLFE*/, "Side"
2242 };
Mattc7d4b2f2005-06-27 14:59:41 +02002243 hda_nid_t nid;
2244 int i, err;
2245
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002246 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002247 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002248
2249
Mattc7d4b2f2005-06-27 14:59:41 +02002250 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002251 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002252 continue;
2253
2254 nid = spec->multiout.dac_nids[i];
2255
2256 if (i == 2) {
2257 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002258 err = create_controls(spec, "Center", nid, 1);
2259 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002260 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002261 err = create_controls(spec, "LFE", nid, 2);
2262 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002263 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002264
2265 wid_caps = get_wcaps(codec, nid);
2266
2267 if (wid_caps & AC_WCAP_LR_SWAP) {
2268 err = stac92xx_add_control(spec,
2269 STAC_CTL_WIDGET_CLFE_SWITCH,
2270 "Swap Center/LFE Playback Switch", nid);
2271
2272 if (err < 0)
2273 return err;
2274 }
2275
Mattc7d4b2f2005-06-27 14:59:41 +02002276 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002277 err = create_controls(spec, chname[i], nid, 3);
2278 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002279 return err;
2280 }
2281 }
2282
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002283 if (spec->line_switch) {
2284 nid = cfg->input_pins[AUTO_PIN_LINE];
2285 pincap = snd_hda_param_read(codec, nid,
2286 AC_PAR_PIN_CAP);
2287 if (pincap & AC_PINCAP_OUT) {
2288 err = stac92xx_add_control(spec,
2289 STAC_CTL_WIDGET_IO_SWITCH,
2290 "Line In as Output Switch", nid << 8);
2291 if (err < 0)
2292 return err;
2293 }
2294 }
Matt Porter403d1942005-11-29 15:00:51 +01002295
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002296 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002297 unsigned int def_conf;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002298 nid = cfg->input_pins[AUTO_PIN_MIC];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002299 def_conf = snd_hda_codec_read(codec, nid, 0,
2300 AC_VERB_GET_CONFIG_DEFAULT, 0);
2301
2302 /* some laptops have an internal analog microphone
2303 * which can't be used as a output */
2304 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2305 pincap = snd_hda_param_read(codec, nid,
2306 AC_PAR_PIN_CAP);
2307 if (pincap & AC_PINCAP_OUT) {
2308 err = stac92xx_add_control(spec,
2309 STAC_CTL_WIDGET_IO_SWITCH,
2310 "Mic as Output Switch", (nid << 8) | 1);
2311 if (err < 0)
2312 return err;
2313 }
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002314 }
2315 }
Matt Porter403d1942005-11-29 15:00:51 +01002316
Mattc7d4b2f2005-06-27 14:59:41 +02002317 return 0;
2318}
2319
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002320static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2321{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002322 if (is_in_dac_nids(spec, nid))
2323 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002324 if (spec->multiout.hp_nid == nid)
2325 return 1;
2326 return 0;
2327}
2328
2329static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2330{
2331 if (!spec->multiout.hp_nid)
2332 spec->multiout.hp_nid = nid;
2333 else if (spec->multiout.num_dacs > 4) {
2334 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2335 return 1;
2336 } else {
2337 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2338 spec->multiout.num_dacs++;
2339 }
2340 return 0;
2341}
2342
2343/* add playback controls for Speaker and HP outputs */
2344static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2345 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002346{
2347 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002348 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002349 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002350
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002351 old_num_dacs = spec->multiout.num_dacs;
2352 for (i = 0; i < cfg->hp_outs; i++) {
2353 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2354 if (wid_caps & AC_WCAP_UNSOL_CAP)
2355 spec->hp_detect = 1;
2356 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2357 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2358 if (check_in_dac_nids(spec, nid))
2359 nid = 0;
2360 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002361 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002362 add_spec_dacs(spec, nid);
2363 }
2364 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002365 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002366 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2367 if (check_in_dac_nids(spec, nid))
2368 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002369 if (! nid)
2370 continue;
2371 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002372 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002373 for (i = 0; i < cfg->line_outs; i++) {
2374 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2375 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2376 if (check_in_dac_nids(spec, nid))
2377 nid = 0;
2378 if (! nid)
2379 continue;
2380 add_spec_dacs(spec, nid);
2381 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002382 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2383 static const char *pfxs[] = {
2384 "Speaker", "External Speaker", "Speaker2",
2385 };
2386 err = create_controls(spec, pfxs[i - old_num_dacs],
2387 spec->multiout.dac_nids[i], 3);
2388 if (err < 0)
2389 return err;
2390 }
2391 if (spec->multiout.hp_nid) {
2392 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002393 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002394 pfx = "Master";
2395 else
2396 pfx = "Headphone";
2397 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2398 if (err < 0)
2399 return err;
2400 }
Mattc7d4b2f2005-06-27 14:59:41 +02002401
2402 return 0;
2403}
2404
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002405/* labels for mono mux outputs */
2406static const char *stac92xx_mono_labels[3] = {
2407 "DAC0", "DAC1", "Mixer"
2408};
2409
2410/* create mono mux for mono out on capable codecs */
2411static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2412{
2413 struct sigmatel_spec *spec = codec->spec;
2414 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2415 int i, num_cons;
2416 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2417
2418 num_cons = snd_hda_get_connections(codec,
2419 spec->mono_nid,
2420 con_lst,
2421 HDA_MAX_NUM_INPUTS);
2422 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2423 return -EINVAL;
2424
2425 for (i = 0; i < num_cons; i++) {
2426 mono_mux->items[mono_mux->num_items].label =
2427 stac92xx_mono_labels[i];
2428 mono_mux->items[mono_mux->num_items].index = i;
2429 mono_mux->num_items++;
2430 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002431
2432 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2433 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002434}
2435
Matt Porter8b657272006-10-26 17:12:59 +02002436/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002437static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002438 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2439 "Digital Mic 3", "Digital Mic 4"
2440};
2441
2442/* create playback/capture controls for input pins on dmic capable codecs */
2443static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2444 const struct auto_pin_cfg *cfg)
2445{
2446 struct sigmatel_spec *spec = codec->spec;
2447 struct hda_input_mux *dimux = &spec->private_dimux;
2448 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002449 int err, i, j;
2450 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002451
2452 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2453 dimux->items[dimux->num_items].index = 0;
2454 dimux->num_items++;
2455
2456 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002457 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002458 int index;
2459 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002460 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002461 unsigned int def_conf;
2462
2463 def_conf = snd_hda_codec_read(codec,
2464 spec->dmic_nids[i],
2465 0,
2466 AC_VERB_GET_CONFIG_DEFAULT,
2467 0);
2468 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2469 continue;
2470
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002471 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002472 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002473 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002474 con_lst,
2475 HDA_MAX_NUM_INPUTS);
2476 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002477 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002478 index = j;
2479 goto found;
2480 }
2481 continue;
2482found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002483 wcaps = get_wcaps(codec, nid);
2484
2485 if (wcaps & AC_WCAP_OUT_AMP) {
2486 sprintf(name, "%s Capture Volume",
2487 stac92xx_dmic_labels[dimux->num_items]);
2488
2489 err = stac92xx_add_control(spec,
2490 STAC_CTL_WIDGET_VOL,
2491 name,
2492 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2493 if (err < 0)
2494 return err;
2495 }
2496
Matt Porter8b657272006-10-26 17:12:59 +02002497 dimux->items[dimux->num_items].label =
2498 stac92xx_dmic_labels[dimux->num_items];
2499 dimux->items[dimux->num_items].index = index;
2500 dimux->num_items++;
2501 }
2502
2503 return 0;
2504}
2505
Mattc7d4b2f2005-06-27 14:59:41 +02002506/* create playback/capture controls for input pins */
2507static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2508{
2509 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002510 struct hda_input_mux *imux = &spec->private_imux;
2511 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2512 int i, j, k;
2513
2514 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002515 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002516
Takashi Iwai314634b2006-09-21 11:56:18 +02002517 if (!cfg->input_pins[i])
2518 continue;
2519 index = -1;
2520 for (j = 0; j < spec->num_muxes; j++) {
2521 int num_cons;
2522 num_cons = snd_hda_get_connections(codec,
2523 spec->mux_nids[j],
2524 con_lst,
2525 HDA_MAX_NUM_INPUTS);
2526 for (k = 0; k < num_cons; k++)
2527 if (con_lst[k] == cfg->input_pins[i]) {
2528 index = k;
2529 goto found;
2530 }
Mattc7d4b2f2005-06-27 14:59:41 +02002531 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002532 continue;
2533 found:
2534 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2535 imux->items[imux->num_items].index = index;
2536 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002537 }
2538
Steve Longerbeam7b043892007-05-03 20:50:03 +02002539 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002540 /*
2541 * Set the current input for the muxes.
2542 * The STAC9221 has two input muxes with identical source
2543 * NID lists. Hopefully this won't get confused.
2544 */
2545 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002546 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2547 AC_VERB_SET_CONNECT_SEL,
2548 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002549 }
2550 }
2551
Mattc7d4b2f2005-06-27 14:59:41 +02002552 return 0;
2553}
2554
Mattc7d4b2f2005-06-27 14:59:41 +02002555static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2556{
2557 struct sigmatel_spec *spec = codec->spec;
2558 int i;
2559
2560 for (i = 0; i < spec->autocfg.line_outs; i++) {
2561 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2562 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2563 }
2564}
2565
2566static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2567{
2568 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002569 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002570
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002571 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2572 hda_nid_t pin;
2573 pin = spec->autocfg.hp_pins[i];
2574 if (pin) /* connect to front */
2575 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2576 }
2577 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2578 hda_nid_t pin;
2579 pin = spec->autocfg.speaker_pins[i];
2580 if (pin) /* connect to front */
2581 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2582 }
Mattc7d4b2f2005-06-27 14:59:41 +02002583}
2584
Matt Porter3cc08dc2006-01-23 15:27:49 +01002585static 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 +02002586{
2587 struct sigmatel_spec *spec = codec->spec;
2588 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002589 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002590
Matt Porter8b657272006-10-26 17:12:59 +02002591 if ((err = snd_hda_parse_pin_def_config(codec,
2592 &spec->autocfg,
2593 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002594 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002595 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002596 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002597
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002598 /* If we have no real line-out pin and multiple hp-outs, HPs should
2599 * be set up as multi-channel outputs.
2600 */
2601 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2602 spec->autocfg.hp_outs > 1) {
2603 /* Copy hp_outs to line_outs, backup line_outs in
2604 * speaker_outs so that the following routines can handle
2605 * HP pins as primary outputs.
2606 */
2607 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2608 sizeof(spec->autocfg.line_out_pins));
2609 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2610 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2611 sizeof(spec->autocfg.hp_pins));
2612 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2613 hp_speaker_swap = 1;
2614 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002615 if (spec->autocfg.mono_out_pin) {
2616 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2617 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2618 u32 caps = query_amp_caps(codec,
2619 spec->autocfg.mono_out_pin, dir);
2620 hda_nid_t conn_list[1];
2621
2622 /* get the mixer node and then the mono mux if it exists */
2623 if (snd_hda_get_connections(codec,
2624 spec->autocfg.mono_out_pin, conn_list, 1) &&
2625 snd_hda_get_connections(codec, conn_list[0],
2626 conn_list, 1)) {
2627
2628 int wcaps = get_wcaps(codec, conn_list[0]);
2629 int wid_type = (wcaps & AC_WCAP_TYPE)
2630 >> AC_WCAP_TYPE_SHIFT;
2631 /* LR swap check, some stac925x have a mux that
2632 * changes the DACs output path instead of the
2633 * mono-mux path.
2634 */
2635 if (wid_type == AC_WID_AUD_SEL &&
2636 !(wcaps & AC_WCAP_LR_SWAP))
2637 spec->mono_nid = conn_list[0];
2638 }
2639 /* all mono outs have a least a mute/unmute switch */
2640 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2641 "Mono Playback Switch",
2642 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2643 1, 0, dir));
2644 if (err < 0)
2645 return err;
2646 /* check to see if there is volume support for the amp */
2647 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2648 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2649 "Mono Playback Volume",
2650 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2651 1, 0, dir));
2652 if (err < 0)
2653 return err;
2654 }
2655
2656 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2657 AC_PINCTL_OUT_EN);
2658 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002659
Matt Porter403d1942005-11-29 15:00:51 +01002660 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2661 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002662 if (spec->multiout.num_dacs == 0)
2663 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2664 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002665
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002666 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2667
2668 if (err < 0)
2669 return err;
2670
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002671 if (hp_speaker_swap == 1) {
2672 /* Restore the hp_outs and line_outs */
2673 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2674 sizeof(spec->autocfg.line_out_pins));
2675 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2676 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2677 sizeof(spec->autocfg.speaker_pins));
2678 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2679 memset(spec->autocfg.speaker_pins, 0,
2680 sizeof(spec->autocfg.speaker_pins));
2681 spec->autocfg.speaker_outs = 0;
2682 }
2683
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002684 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2685
2686 if (err < 0)
2687 return err;
2688
2689 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2690
2691 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002692 return err;
2693
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002694 if (spec->mono_nid > 0) {
2695 err = stac92xx_auto_create_mono_output_ctls(codec);
2696 if (err < 0)
2697 return err;
2698 }
2699
Matt Porter8b657272006-10-26 17:12:59 +02002700 if (spec->num_dmics > 0)
2701 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2702 &spec->autocfg)) < 0)
2703 return err;
2704
Mattc7d4b2f2005-06-27 14:59:41 +02002705 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002706 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002707 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002708
Takashi Iwai82bc9552006-03-21 11:24:42 +01002709 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002710 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002711 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002712 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002713
2714 if (spec->kctl_alloc)
2715 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2716
2717 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002718 if (!spec->dinput_mux)
2719 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002720 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002721
2722 return 1;
2723}
2724
Takashi Iwai82bc9552006-03-21 11:24:42 +01002725/* add playback controls for HP output */
2726static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2727 struct auto_pin_cfg *cfg)
2728{
2729 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002730 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002731 unsigned int wid_caps;
2732
2733 if (! pin)
2734 return 0;
2735
2736 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002737 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002738 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002739
2740 return 0;
2741}
2742
Richard Fish160ea0d2006-09-06 13:58:25 +02002743/* add playback controls for LFE output */
2744static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2745 struct auto_pin_cfg *cfg)
2746{
2747 struct sigmatel_spec *spec = codec->spec;
2748 int err;
2749 hda_nid_t lfe_pin = 0x0;
2750 int i;
2751
2752 /*
2753 * search speaker outs and line outs for a mono speaker pin
2754 * with an amp. If one is found, add LFE controls
2755 * for it.
2756 */
2757 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2758 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2759 unsigned long wcaps = get_wcaps(codec, pin);
2760 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2761 if (wcaps == AC_WCAP_OUT_AMP)
2762 /* found a mono speaker with an amp, must be lfe */
2763 lfe_pin = pin;
2764 }
2765
2766 /* if speaker_outs is 0, then speakers may be in line_outs */
2767 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2768 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2769 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2770 unsigned long cfg;
2771 cfg = snd_hda_codec_read(codec, pin, 0,
2772 AC_VERB_GET_CONFIG_DEFAULT,
2773 0x00);
2774 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2775 unsigned long wcaps = get_wcaps(codec, pin);
2776 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2777 if (wcaps == AC_WCAP_OUT_AMP)
2778 /* found a mono speaker with an amp,
2779 must be lfe */
2780 lfe_pin = pin;
2781 }
2782 }
2783 }
2784
2785 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002786 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002787 if (err < 0)
2788 return err;
2789 }
2790
2791 return 0;
2792}
2793
Mattc7d4b2f2005-06-27 14:59:41 +02002794static int stac9200_parse_auto_config(struct hda_codec *codec)
2795{
2796 struct sigmatel_spec *spec = codec->spec;
2797 int err;
2798
Kailang Yangdf694da2005-12-05 19:42:22 +01002799 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002800 return err;
2801
2802 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2803 return err;
2804
Takashi Iwai82bc9552006-03-21 11:24:42 +01002805 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2806 return err;
2807
Richard Fish160ea0d2006-09-06 13:58:25 +02002808 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2809 return err;
2810
Takashi Iwai82bc9552006-03-21 11:24:42 +01002811 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002812 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002813 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002814 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002815
2816 if (spec->kctl_alloc)
2817 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2818
2819 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002820 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002821
2822 return 1;
2823}
2824
Sam Revitch62fe78e2006-05-10 15:09:17 +02002825/*
2826 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2827 * funky external mute control using GPIO pins.
2828 */
2829
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002830static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002831 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002832{
2833 unsigned int gpiostate, gpiomask, gpiodir;
2834
2835 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2836 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002837 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002838
2839 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2840 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002841 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002842
2843 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2844 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002845 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002846
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002847 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002848 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2849
2850 snd_hda_codec_write(codec, codec->afg, 0,
2851 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002852 snd_hda_codec_read(codec, codec->afg, 0,
2853 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002854
2855 msleep(1);
2856
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002857 snd_hda_codec_read(codec, codec->afg, 0,
2858 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002859}
2860
Takashi Iwai314634b2006-09-21 11:56:18 +02002861static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2862 unsigned int event)
2863{
2864 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002865 snd_hda_codec_write_cache(codec, nid, 0,
2866 AC_VERB_SET_UNSOLICITED_ENABLE,
2867 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002868}
2869
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002870static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2871{
2872 int i;
2873 for (i = 0; i < cfg->hp_outs; i++)
2874 if (cfg->hp_pins[i] == nid)
2875 return 1; /* nid is a HP-Out */
2876
2877 return 0; /* nid is not a HP-Out */
2878};
2879
Mattc7d4b2f2005-06-27 14:59:41 +02002880static int stac92xx_init(struct hda_codec *codec)
2881{
2882 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002883 struct auto_pin_cfg *cfg = &spec->autocfg;
2884 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002885
Mattc7d4b2f2005-06-27 14:59:41 +02002886 snd_hda_sequence_write(codec, spec->init);
2887
Takashi Iwai82bc9552006-03-21 11:24:42 +01002888 /* set up pins */
2889 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002890 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002891 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002892 enable_pin_detect(codec, cfg->hp_pins[i],
2893 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002894 /* force to enable the first line-out; the others are set up
2895 * in unsol_event
2896 */
2897 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2898 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002899 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002900 /* fake event to set up pins */
2901 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2902 } else {
2903 stac92xx_auto_init_multi_out(codec);
2904 stac92xx_auto_init_hp_out(codec);
2905 }
2906 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002907 hda_nid_t nid = cfg->input_pins[i];
2908 if (nid) {
2909 unsigned int pinctl = AC_PINCTL_IN_EN;
2910 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2911 pinctl |= stac92xx_get_vref(codec, nid);
2912 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2913 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002914 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002915 for (i = 0; i < spec->num_dmics; i++)
2916 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2917 AC_PINCTL_IN_EN);
2918 for (i = 0; i < spec->num_pwrs; i++) {
2919 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2920 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2921 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2922 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2923 /* outputs are only ports capable of power management
2924 * any attempts on powering down a input port cause the
2925 * referenced VREF to act quirky.
2926 */
2927 if (pinctl & AC_PINCTL_IN_EN)
2928 continue;
2929 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2930 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2931 }
Matt Porter8b657272006-10-26 17:12:59 +02002932
Takashi Iwai82bc9552006-03-21 11:24:42 +01002933 if (cfg->dig_out_pin)
2934 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2935 AC_PINCTL_OUT_EN);
2936 if (cfg->dig_in_pin)
2937 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2938 AC_PINCTL_IN_EN);
2939
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002940 stac_gpio_set(codec, spec->gpio_mask,
2941 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002942
Mattc7d4b2f2005-06-27 14:59:41 +02002943 return 0;
2944}
2945
Matt2f2f4252005-04-13 14:45:30 +02002946static void stac92xx_free(struct hda_codec *codec)
2947{
Mattc7d4b2f2005-06-27 14:59:41 +02002948 struct sigmatel_spec *spec = codec->spec;
2949 int i;
2950
2951 if (! spec)
2952 return;
2953
2954 if (spec->kctl_alloc) {
2955 for (i = 0; i < spec->num_kctl_used; i++)
2956 kfree(spec->kctl_alloc[i].name);
2957 kfree(spec->kctl_alloc);
2958 }
2959
Richard Fish11b44bb2006-08-23 18:31:34 +02002960 if (spec->bios_pin_configs)
2961 kfree(spec->bios_pin_configs);
2962
Mattc7d4b2f2005-06-27 14:59:41 +02002963 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002964}
2965
Matt4e550962005-07-04 17:51:39 +02002966static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2967 unsigned int flag)
2968{
2969 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2970 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002971
Takashi Iwaif9acba42007-05-29 18:01:06 +02002972 if (pin_ctl & AC_PINCTL_IN_EN) {
2973 /*
2974 * we need to check the current set-up direction of
2975 * shared input pins since they can be switched via
2976 * "xxx as Output" mixer switch
2977 */
2978 struct sigmatel_spec *spec = codec->spec;
2979 struct auto_pin_cfg *cfg = &spec->autocfg;
2980 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2981 spec->line_switch) ||
2982 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
2983 spec->mic_switch))
2984 return;
2985 }
2986
Steve Longerbeam7b043892007-05-03 20:50:03 +02002987 /* if setting pin direction bits, clear the current
2988 direction bits first */
2989 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
2990 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
2991
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002992 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02002993 AC_VERB_SET_PIN_WIDGET_CONTROL,
2994 pin_ctl | flag);
2995}
2996
2997static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
2998 unsigned int flag)
2999{
3000 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3001 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003002 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003003 AC_VERB_SET_PIN_WIDGET_CONTROL,
3004 pin_ctl & ~flag);
3005}
3006
Jiang Zhe40c1d302007-11-12 13:05:16 +01003007static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003008{
3009 if (!nid)
3010 return 0;
3011 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003012 & (1 << 31)) {
3013 unsigned int pinctl;
3014 pinctl = snd_hda_codec_read(codec, nid, 0,
3015 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3016 if (pinctl & AC_PINCTL_IN_EN)
3017 return 0; /* mic- or line-input */
3018 else
3019 return 1; /* HP-output */
3020 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003021 return 0;
3022}
3023
3024static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003025{
3026 struct sigmatel_spec *spec = codec->spec;
3027 struct auto_pin_cfg *cfg = &spec->autocfg;
3028 int i, presence;
3029
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003030 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003031 if (spec->gpio_mute)
3032 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3033 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3034
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003035 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003036 if (presence)
3037 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003038 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003039 }
Matt4e550962005-07-04 17:51:39 +02003040
3041 if (presence) {
3042 /* disable lineouts, enable hp */
3043 for (i = 0; i < cfg->line_outs; i++)
3044 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3045 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003046 for (i = 0; i < cfg->speaker_outs; i++)
3047 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3048 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003049 } else {
3050 /* enable lineouts, disable hp */
3051 for (i = 0; i < cfg->line_outs; i++)
3052 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3053 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003054 for (i = 0; i < cfg->speaker_outs; i++)
3055 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3056 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003057 }
3058}
3059
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003060static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3061{
3062 struct sigmatel_spec *spec = codec->spec;
3063 hda_nid_t nid = spec->pwr_nids[idx];
3064 int presence, val;
3065 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3066 & 0x000000ff;
3067 presence = get_hp_pin_presence(codec, nid);
3068 idx = 1 << idx;
3069
3070 if (presence)
3071 val &= ~idx;
3072 else
3073 val |= idx;
3074
3075 /* power down unused output ports */
3076 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3077};
3078
Takashi Iwai314634b2006-09-21 11:56:18 +02003079static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3080{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003081 struct sigmatel_spec *spec = codec->spec;
3082 int idx = res >> 26 & 0x0f;
3083
3084 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003085 case STAC_HP_EVENT:
3086 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003087 /* fallthru */
3088 case STAC_PWR_EVENT:
3089 if (spec->num_pwrs > 0)
3090 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003091 }
3092}
3093
Takashi Iwaicb53c622007-08-10 17:21:45 +02003094#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003095static int stac92xx_resume(struct hda_codec *codec)
3096{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003097 struct sigmatel_spec *spec = codec->spec;
3098
Richard Fish11b44bb2006-08-23 18:31:34 +02003099 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003100 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003101 stac_gpio_set(codec, spec->gpio_mask,
3102 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003103 snd_hda_codec_resume_amp(codec);
3104 snd_hda_codec_resume_cache(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003105 /* invoke unsolicited event to reset the HP state */
3106 if (spec->hp_detect)
3107 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003108 return 0;
3109}
3110#endif
3111
Matt2f2f4252005-04-13 14:45:30 +02003112static struct hda_codec_ops stac92xx_patch_ops = {
3113 .build_controls = stac92xx_build_controls,
3114 .build_pcms = stac92xx_build_pcms,
3115 .init = stac92xx_init,
3116 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003117 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003118#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003119 .resume = stac92xx_resume,
3120#endif
Matt2f2f4252005-04-13 14:45:30 +02003121};
3122
3123static int patch_stac9200(struct hda_codec *codec)
3124{
3125 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003126 int err;
Matt2f2f4252005-04-13 14:45:30 +02003127
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003128 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003129 if (spec == NULL)
3130 return -ENOMEM;
3131
3132 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003133 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003134 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003135 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3136 stac9200_models,
3137 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003138 if (spec->board_config < 0) {
3139 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3140 err = stac92xx_save_bios_config_regs(codec);
3141 if (err < 0) {
3142 stac92xx_free(codec);
3143 return err;
3144 }
3145 spec->pin_configs = spec->bios_pin_configs;
3146 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003147 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3148 stac92xx_set_config_regs(codec);
3149 }
Matt2f2f4252005-04-13 14:45:30 +02003150
3151 spec->multiout.max_channels = 2;
3152 spec->multiout.num_dacs = 1;
3153 spec->multiout.dac_nids = stac9200_dac_nids;
3154 spec->adc_nids = stac9200_adc_nids;
3155 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003156 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003157 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003158 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003159 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003160
Tobin Davisbf277782008-02-03 20:31:47 +01003161 if (spec->board_config == STAC_9200_GATEWAY ||
3162 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003163 spec->init = stac9200_eapd_init;
3164 else
3165 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003166 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003167
3168 err = stac9200_parse_auto_config(codec);
3169 if (err < 0) {
3170 stac92xx_free(codec);
3171 return err;
3172 }
Matt2f2f4252005-04-13 14:45:30 +02003173
3174 codec->patch_ops = stac92xx_patch_ops;
3175
3176 return 0;
3177}
3178
Tobin Davis8e21c342007-01-08 11:04:17 +01003179static int patch_stac925x(struct hda_codec *codec)
3180{
3181 struct sigmatel_spec *spec;
3182 int err;
3183
3184 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3185 if (spec == NULL)
3186 return -ENOMEM;
3187
3188 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003189 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003190 spec->pin_nids = stac925x_pin_nids;
3191 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3192 stac925x_models,
3193 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003194 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003195 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003196 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3197 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003198 err = stac92xx_save_bios_config_regs(codec);
3199 if (err < 0) {
3200 stac92xx_free(codec);
3201 return err;
3202 }
3203 spec->pin_configs = spec->bios_pin_configs;
3204 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3205 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3206 stac92xx_set_config_regs(codec);
3207 }
3208
3209 spec->multiout.max_channels = 2;
3210 spec->multiout.num_dacs = 1;
3211 spec->multiout.dac_nids = stac925x_dac_nids;
3212 spec->adc_nids = stac925x_adc_nids;
3213 spec->mux_nids = stac925x_mux_nids;
3214 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003215 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003216 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003217 switch (codec->vendor_id) {
3218 case 0x83847632: /* STAC9202 */
3219 case 0x83847633: /* STAC9202D */
3220 case 0x83847636: /* STAC9251 */
3221 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003222 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003223 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003224 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3225 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003226 break;
3227 default:
3228 spec->num_dmics = 0;
3229 break;
3230 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003231
3232 spec->init = stac925x_core_init;
3233 spec->mixer = stac925x_mixer;
3234
3235 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003236 if (!err) {
3237 if (spec->board_config < 0) {
3238 printk(KERN_WARNING "hda_codec: No auto-config is "
3239 "available, default to model=ref\n");
3240 spec->board_config = STAC_925x_REF;
3241 goto again;
3242 }
3243 err = -EINVAL;
3244 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003245 if (err < 0) {
3246 stac92xx_free(codec);
3247 return err;
3248 }
3249
3250 codec->patch_ops = stac92xx_patch_ops;
3251
3252 return 0;
3253}
3254
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003255static struct hda_input_mux stac92hd73xx_dmux = {
3256 .num_items = 4,
3257 .items = {
3258 { "Analog Inputs", 0x0b },
3259 { "CD", 0x08 },
3260 { "Digital Mic 1", 0x09 },
3261 { "Digital Mic 2", 0x0a },
3262 }
3263};
3264
3265static int patch_stac92hd73xx(struct hda_codec *codec)
3266{
3267 struct sigmatel_spec *spec;
3268 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3269 int err = 0;
3270
3271 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3272 if (spec == NULL)
3273 return -ENOMEM;
3274
3275 codec->spec = spec;
3276 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3277 spec->pin_nids = stac92hd73xx_pin_nids;
3278 spec->board_config = snd_hda_check_board_config(codec,
3279 STAC_92HD73XX_MODELS,
3280 stac92hd73xx_models,
3281 stac92hd73xx_cfg_tbl);
3282again:
3283 if (spec->board_config < 0) {
3284 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3285 " STAC92HD73XX, using BIOS defaults\n");
3286 err = stac92xx_save_bios_config_regs(codec);
3287 if (err < 0) {
3288 stac92xx_free(codec);
3289 return err;
3290 }
3291 spec->pin_configs = spec->bios_pin_configs;
3292 } else {
3293 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3294 stac92xx_set_config_regs(codec);
3295 }
3296
3297 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3298 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3299
3300 if (spec->multiout.num_dacs < 0) {
3301 printk(KERN_WARNING "hda_codec: Could not determine "
3302 "number of channels defaulting to DAC count\n");
3303 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3304 }
3305
3306 switch (spec->multiout.num_dacs) {
3307 case 0x3: /* 6 Channel */
3308 spec->mixer = stac92hd73xx_6ch_mixer;
3309 spec->init = stac92hd73xx_6ch_core_init;
3310 break;
3311 case 0x4: /* 8 Channel */
3312 spec->multiout.hp_nid = 0x18;
3313 spec->mixer = stac92hd73xx_8ch_mixer;
3314 spec->init = stac92hd73xx_8ch_core_init;
3315 break;
3316 case 0x5: /* 10 Channel */
3317 spec->multiout.hp_nid = 0x19;
3318 spec->mixer = stac92hd73xx_10ch_mixer;
3319 spec->init = stac92hd73xx_10ch_core_init;
3320 };
3321
3322 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3323 spec->aloopback_mask = 0x01;
3324 spec->aloopback_shift = 8;
3325
3326 spec->mux_nids = stac92hd73xx_mux_nids;
3327 spec->adc_nids = stac92hd73xx_adc_nids;
3328 spec->dmic_nids = stac92hd73xx_dmic_nids;
3329 spec->dmux_nids = stac92hd73xx_dmux_nids;
3330
3331 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3332 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3333 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003334 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003335 spec->dinput_mux = &stac92hd73xx_dmux;
3336 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003337 spec->gpio_mask = spec->gpio_dir = 0x1;
3338 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003339
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003340 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3341 spec->pwr_nids = stac92hd73xx_pwr_nids;
3342
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003343 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3344
3345 if (!err) {
3346 if (spec->board_config < 0) {
3347 printk(KERN_WARNING "hda_codec: No auto-config is "
3348 "available, default to model=ref\n");
3349 spec->board_config = STAC_92HD73XX_REF;
3350 goto again;
3351 }
3352 err = -EINVAL;
3353 }
3354
3355 if (err < 0) {
3356 stac92xx_free(codec);
3357 return err;
3358 }
3359
3360 codec->patch_ops = stac92xx_patch_ops;
3361
3362 return 0;
3363}
3364
Matthew Ranostaye035b842007-11-06 11:53:55 +01003365static int patch_stac92hd71bxx(struct hda_codec *codec)
3366{
3367 struct sigmatel_spec *spec;
3368 int err = 0;
3369
3370 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3371 if (spec == NULL)
3372 return -ENOMEM;
3373
3374 codec->spec = spec;
3375 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3376 spec->pin_nids = stac92hd71bxx_pin_nids;
3377 spec->board_config = snd_hda_check_board_config(codec,
3378 STAC_92HD71BXX_MODELS,
3379 stac92hd71bxx_models,
3380 stac92hd71bxx_cfg_tbl);
3381again:
3382 if (spec->board_config < 0) {
3383 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3384 " STAC92HD71BXX, using BIOS defaults\n");
3385 err = stac92xx_save_bios_config_regs(codec);
3386 if (err < 0) {
3387 stac92xx_free(codec);
3388 return err;
3389 }
3390 spec->pin_configs = spec->bios_pin_configs;
3391 } else {
3392 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3393 stac92xx_set_config_regs(codec);
3394 }
3395
Matthew Ranostay541eee82007-12-14 12:08:04 +01003396 switch (codec->vendor_id) {
3397 case 0x111d76b6: /* 4 Port without Analog Mixer */
3398 case 0x111d76b7:
3399 case 0x111d76b4: /* 6 Port without Analog Mixer */
3400 case 0x111d76b5:
3401 spec->mixer = stac92hd71bxx_mixer;
3402 spec->init = stac92hd71bxx_core_init;
3403 break;
3404 default:
3405 spec->mixer = stac92hd71bxx_analog_mixer;
3406 spec->init = stac92hd71bxx_analog_core_init;
3407 }
3408
3409 spec->aloopback_mask = 0x20;
3410 spec->aloopback_shift = 0;
3411
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003412 /* GPIO0 High = EAPD */
3413 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003414
Matthew Ranostaye035b842007-11-06 11:53:55 +01003415 spec->mux_nids = stac92hd71bxx_mux_nids;
3416 spec->adc_nids = stac92hd71bxx_adc_nids;
3417 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003418 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003419
3420 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3421 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3422 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003423 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003424
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003425 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3426 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3427
Matthew Ranostaye035b842007-11-06 11:53:55 +01003428 spec->multiout.num_dacs = 2;
3429 spec->multiout.hp_nid = 0x11;
3430 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3431
3432 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3433 if (!err) {
3434 if (spec->board_config < 0) {
3435 printk(KERN_WARNING "hda_codec: No auto-config is "
3436 "available, default to model=ref\n");
3437 spec->board_config = STAC_92HD71BXX_REF;
3438 goto again;
3439 }
3440 err = -EINVAL;
3441 }
3442
3443 if (err < 0) {
3444 stac92xx_free(codec);
3445 return err;
3446 }
3447
3448 codec->patch_ops = stac92xx_patch_ops;
3449
3450 return 0;
3451};
3452
Matt2f2f4252005-04-13 14:45:30 +02003453static int patch_stac922x(struct hda_codec *codec)
3454{
3455 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003456 int err;
Matt2f2f4252005-04-13 14:45:30 +02003457
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003458 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003459 if (spec == NULL)
3460 return -ENOMEM;
3461
3462 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003463 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003464 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003465 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3466 stac922x_models,
3467 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003468 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003469 spec->gpio_mask = spec->gpio_dir = 0x03;
3470 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003471 /* Intel Macs have all same PCI SSID, so we need to check
3472 * codec SSID to distinguish the exact models
3473 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003474 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003475 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003476
3477 case 0x106b0800:
3478 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003479 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003480 case 0x106b0600:
3481 case 0x106b0700:
3482 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003483 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003484 case 0x106b0e00:
3485 case 0x106b0f00:
3486 case 0x106b1600:
3487 case 0x106b1700:
3488 case 0x106b0200:
3489 case 0x106b1e00:
3490 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003491 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003492 case 0x106b1a00:
3493 case 0x00000100:
3494 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003495 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003496 case 0x106b0a00:
3497 case 0x106b2200:
3498 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003499 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003500 }
3501 }
3502
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003503 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003504 if (spec->board_config < 0) {
3505 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3506 "using BIOS defaults\n");
3507 err = stac92xx_save_bios_config_regs(codec);
3508 if (err < 0) {
3509 stac92xx_free(codec);
3510 return err;
3511 }
3512 spec->pin_configs = spec->bios_pin_configs;
3513 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003514 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3515 stac92xx_set_config_regs(codec);
3516 }
Matt2f2f4252005-04-13 14:45:30 +02003517
Matt2f2f4252005-04-13 14:45:30 +02003518 spec->adc_nids = stac922x_adc_nids;
3519 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003520 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003521 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003522 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003523 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003524
3525 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003526 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003527
3528 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003529
Matt Porter3cc08dc2006-01-23 15:27:49 +01003530 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003531 if (!err) {
3532 if (spec->board_config < 0) {
3533 printk(KERN_WARNING "hda_codec: No auto-config is "
3534 "available, default to model=ref\n");
3535 spec->board_config = STAC_D945_REF;
3536 goto again;
3537 }
3538 err = -EINVAL;
3539 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003540 if (err < 0) {
3541 stac92xx_free(codec);
3542 return err;
3543 }
3544
3545 codec->patch_ops = stac92xx_patch_ops;
3546
Takashi Iwai807a46362007-05-29 19:01:37 +02003547 /* Fix Mux capture level; max to 2 */
3548 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3549 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3550 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3551 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3552 (0 << AC_AMPCAP_MUTE_SHIFT));
3553
Matt Porter3cc08dc2006-01-23 15:27:49 +01003554 return 0;
3555}
3556
3557static int patch_stac927x(struct hda_codec *codec)
3558{
3559 struct sigmatel_spec *spec;
3560 int err;
3561
3562 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3563 if (spec == NULL)
3564 return -ENOMEM;
3565
3566 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003567 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003568 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003569 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3570 stac927x_models,
3571 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003572 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003573 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3574 if (spec->board_config < 0)
3575 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3576 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003577 err = stac92xx_save_bios_config_regs(codec);
3578 if (err < 0) {
3579 stac92xx_free(codec);
3580 return err;
3581 }
3582 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003583 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003584 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3585 stac92xx_set_config_regs(codec);
3586 }
3587
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003588 spec->adc_nids = stac927x_adc_nids;
3589 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3590 spec->mux_nids = stac927x_mux_nids;
3591 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
3592 spec->multiout.dac_nids = spec->dac_nids;
3593
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003594 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003595 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003596 case STAC_D965_5ST:
3597 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003598 spec->gpio_mask = spec->gpio_dir = 0x01;
3599 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003600 spec->num_dmics = 0;
3601
Tobin Davis93ed1502006-09-01 21:03:12 +02003602 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003603 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003604 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003605 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003606 /* correct the front output jack as a hp out */
3607 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003608 /* correct the front input jack as a mic */
3609 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3610 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003611 case STAC_DELL_3ST:
3612 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003613 spec->gpio_mask = spec->gpio_dir = 0x04;
3614 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003615 spec->dmic_nids = stac927x_dmic_nids;
3616 spec->num_dmics = STAC927X_NUM_DMICS;
3617
Tobin Davis93ed1502006-09-01 21:03:12 +02003618 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003619 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003620 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003621 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003622 break;
3623 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003624 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003625 spec->gpio_mask = spec->gpio_dir = 0x1;
3626 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003627 spec->num_dmics = 0;
3628
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003629 spec->init = stac927x_core_init;
3630 spec->mixer = stac927x_mixer;
3631 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003632
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003633 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003634 spec->aloopback_mask = 0x40;
3635 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003636
Matt Porter3cc08dc2006-01-23 15:27:49 +01003637 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003638 if (!err) {
3639 if (spec->board_config < 0) {
3640 printk(KERN_WARNING "hda_codec: No auto-config is "
3641 "available, default to model=ref\n");
3642 spec->board_config = STAC_D965_REF;
3643 goto again;
3644 }
3645 err = -EINVAL;
3646 }
Mattc7d4b2f2005-06-27 14:59:41 +02003647 if (err < 0) {
3648 stac92xx_free(codec);
3649 return err;
3650 }
Matt2f2f4252005-04-13 14:45:30 +02003651
3652 codec->patch_ops = stac92xx_patch_ops;
3653
Takashi Iwai52987652008-01-16 16:09:47 +01003654 /*
3655 * !!FIXME!!
3656 * The STAC927x seem to require fairly long delays for certain
3657 * command sequences. With too short delays (even if the answer
3658 * is set to RIRB properly), it results in the silence output
3659 * on some hardwares like Dell.
3660 *
3661 * The below flag enables the longer delay (see get_response
3662 * in hda_intel.c).
3663 */
3664 codec->bus->needs_damn_long_delay = 1;
3665
Matt2f2f4252005-04-13 14:45:30 +02003666 return 0;
3667}
3668
Matt Porterf3302a52006-07-31 12:49:34 +02003669static int patch_stac9205(struct hda_codec *codec)
3670{
3671 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003672 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003673
3674 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3675 if (spec == NULL)
3676 return -ENOMEM;
3677
3678 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003679 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003680 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003681 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3682 stac9205_models,
3683 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003684 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003685 if (spec->board_config < 0) {
3686 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3687 err = stac92xx_save_bios_config_regs(codec);
3688 if (err < 0) {
3689 stac92xx_free(codec);
3690 return err;
3691 }
3692 spec->pin_configs = spec->bios_pin_configs;
3693 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003694 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3695 stac92xx_set_config_regs(codec);
3696 }
3697
3698 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003699 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003700 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003701 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003702 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003703 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003704 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003705 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003706 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003707
3708 spec->init = stac9205_core_init;
3709 spec->mixer = stac9205_mixer;
3710
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003711 spec->aloopback_mask = 0x40;
3712 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003713 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003714
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003715 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003716 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003717 /* Enable SPDIF in/out */
3718 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3719 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003720
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003721 /* Enable unsol response for GPIO4/Dock HP connection */
3722 snd_hda_codec_write(codec, codec->afg, 0,
3723 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3724 snd_hda_codec_write_cache(codec, codec->afg, 0,
3725 AC_VERB_SET_UNSOLICITED_ENABLE,
3726 (AC_USRSP_EN | STAC_HP_EVENT));
3727
3728 spec->gpio_dir = 0x0b;
3729 spec->gpio_mask = 0x1b;
3730 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003731 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003732 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003733 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003734 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003735 break;
3736 default:
3737 /* GPIO0 High = EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003738 spec->gpio_mask = spec->gpio_dir = 0x1;
3739 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003740 break;
3741 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003742
Matt Porterf3302a52006-07-31 12:49:34 +02003743 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003744 if (!err) {
3745 if (spec->board_config < 0) {
3746 printk(KERN_WARNING "hda_codec: No auto-config is "
3747 "available, default to model=ref\n");
3748 spec->board_config = STAC_9205_REF;
3749 goto again;
3750 }
3751 err = -EINVAL;
3752 }
Matt Porterf3302a52006-07-31 12:49:34 +02003753 if (err < 0) {
3754 stac92xx_free(codec);
3755 return err;
3756 }
3757
3758 codec->patch_ops = stac92xx_patch_ops;
3759
3760 return 0;
3761}
3762
Matt2f2f4252005-04-13 14:45:30 +02003763/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003764 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003765 */
3766
Guillaume Munch99ccc562006-08-16 19:35:12 +02003767/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003768static hda_nid_t vaio_dacs[] = { 0x2 };
3769#define VAIO_HP_DAC 0x5
3770static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3771static hda_nid_t vaio_mux_nids[] = { 0x15 };
3772
3773static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003774 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003775 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003776 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003777 { "Mic Jack", 0x1 },
3778 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003779 { "PCM", 0x3 },
3780 }
3781};
3782
3783static struct hda_verb vaio_init[] = {
3784 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003785 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003786 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3787 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3788 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3789 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003790 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003791 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3792 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3793 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3794 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3795 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3796 {}
3797};
3798
Guillaume Munch6d859062006-08-22 17:15:47 +02003799static struct hda_verb vaio_ar_init[] = {
3800 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3801 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3802 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3803 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3804/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3805 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003806 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003807 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3808 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3809/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3810 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3811 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3812 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3813 {}
3814};
3815
Takashi Iwaidb064e52006-03-16 16:04:58 +01003816/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003817static struct hda_bind_ctls vaio_bind_master_vol = {
3818 .ops = &snd_hda_bind_vol,
3819 .values = {
3820 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3821 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3822 0
3823 },
3824};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003825
3826/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003827static struct hda_bind_ctls vaio_bind_master_sw = {
3828 .ops = &snd_hda_bind_sw,
3829 .values = {
3830 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3831 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3832 0,
3833 },
3834};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003835
3836static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003837 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3838 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003839 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3840 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3841 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3842 {
3843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3844 .name = "Capture Source",
3845 .count = 1,
3846 .info = stac92xx_mux_enum_info,
3847 .get = stac92xx_mux_enum_get,
3848 .put = stac92xx_mux_enum_put,
3849 },
3850 {}
3851};
3852
Guillaume Munch6d859062006-08-22 17:15:47 +02003853static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003854 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3855 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003856 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3857 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3858 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3859 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3860 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3861 {
3862 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3863 .name = "Capture Source",
3864 .count = 1,
3865 .info = stac92xx_mux_enum_info,
3866 .get = stac92xx_mux_enum_get,
3867 .put = stac92xx_mux_enum_put,
3868 },
3869 {}
3870};
3871
3872static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003873 .build_controls = stac92xx_build_controls,
3874 .build_pcms = stac92xx_build_pcms,
3875 .init = stac92xx_init,
3876 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003877#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003878 .resume = stac92xx_resume,
3879#endif
3880};
3881
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003882static int stac9872_vaio_init(struct hda_codec *codec)
3883{
3884 int err;
3885
3886 err = stac92xx_init(codec);
3887 if (err < 0)
3888 return err;
3889 if (codec->patch_ops.unsol_event)
3890 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3891 return 0;
3892}
3893
3894static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3895{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003896 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003897 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3898 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3899 } else {
3900 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3901 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3902 }
3903}
3904
3905static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3906{
3907 switch (res >> 26) {
3908 case STAC_HP_EVENT:
3909 stac9872_vaio_hp_detect(codec, res);
3910 break;
3911 }
3912}
3913
3914static struct hda_codec_ops stac9872_vaio_patch_ops = {
3915 .build_controls = stac92xx_build_controls,
3916 .build_pcms = stac92xx_build_pcms,
3917 .init = stac9872_vaio_init,
3918 .free = stac92xx_free,
3919 .unsol_event = stac9872_vaio_unsol_event,
3920#ifdef CONFIG_PM
3921 .resume = stac92xx_resume,
3922#endif
3923};
3924
Guillaume Munch6d859062006-08-22 17:15:47 +02003925enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3926 CXD9872RD_VAIO,
3927 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3928 STAC9872AK_VAIO,
3929 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3930 STAC9872K_VAIO,
3931 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003932 CXD9872AKD_VAIO,
3933 STAC_9872_MODELS,
3934};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003935
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003936static const char *stac9872_models[STAC_9872_MODELS] = {
3937 [CXD9872RD_VAIO] = "vaio",
3938 [CXD9872AKD_VAIO] = "vaio-ar",
3939};
3940
3941static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3942 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3943 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3944 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003945 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003946 {}
3947};
3948
Guillaume Munch6d859062006-08-22 17:15:47 +02003949static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003950{
3951 struct sigmatel_spec *spec;
3952 int board_config;
3953
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003954 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3955 stac9872_models,
3956 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003957 if (board_config < 0)
3958 /* unknown config, let generic-parser do its job... */
3959 return snd_hda_parse_generic_codec(codec);
3960
3961 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3962 if (spec == NULL)
3963 return -ENOMEM;
3964
3965 codec->spec = spec;
3966 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003967 case CXD9872RD_VAIO:
3968 case STAC9872AK_VAIO:
3969 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003970 spec->mixer = vaio_mixer;
3971 spec->init = vaio_init;
3972 spec->multiout.max_channels = 2;
3973 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3974 spec->multiout.dac_nids = vaio_dacs;
3975 spec->multiout.hp_nid = VAIO_HP_DAC;
3976 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3977 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003978 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003979 spec->input_mux = &vaio_mux;
3980 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003981 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003982 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02003983
3984 case CXD9872AKD_VAIO:
3985 spec->mixer = vaio_ar_mixer;
3986 spec->init = vaio_ar_init;
3987 spec->multiout.max_channels = 2;
3988 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3989 spec->multiout.dac_nids = vaio_dacs;
3990 spec->multiout.hp_nid = VAIO_HP_DAC;
3991 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003992 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02003993 spec->adc_nids = vaio_adcs;
3994 spec->input_mux = &vaio_mux;
3995 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003996 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02003997 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01003998 }
3999
Takashi Iwaidb064e52006-03-16 16:04:58 +01004000 return 0;
4001}
4002
4003
4004/*
Matt2f2f4252005-04-13 14:45:30 +02004005 * patch entries
4006 */
4007struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4008 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4009 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4010 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4011 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4012 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4013 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4014 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004015 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4016 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4017 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4018 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4019 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4020 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004021 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4022 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4023 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4024 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4025 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4026 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4027 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4028 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4029 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4030 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004031 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4032 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4033 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4034 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4035 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4036 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004037 /* The following does not take into account .id=0x83847661 when subsys =
4038 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4039 * currently not fully supported.
4040 */
4041 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4042 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4043 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004044 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4045 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4046 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4047 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4048 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4049 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4050 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4051 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004052 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4053 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004054 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004055 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4056 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4057 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4058 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4059 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4060 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4061 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4062 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4063 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004064 {} /* terminator */
4065};