blob: 7f506ef0accbc05c9ca0e08e3344b2e06a6d13d1 [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;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100139 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100140
Matt2f2f4252005-04-13 14:45:30 +0200141 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100142 struct hda_input_mux *mono_mux;
143 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200144 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100145 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200146
147 /* capture */
148 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200149 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200150 hda_nid_t *mux_nids;
151 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200152 hda_nid_t *dmic_nids;
153 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100154 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100155 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200156 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100157 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200158
Matt2f2f4252005-04-13 14:45:30 +0200159 /* pin widgets */
160 hda_nid_t *pin_nids;
161 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200162 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200163 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200164
165 /* codec specific stuff */
166 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100167 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200168
169 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200170 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100171 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200172 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100173 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200174
Matt Porter403d1942005-11-29 15:00:51 +0100175 /* i/o switches */
176 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200177 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200178 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200179
Mattc7d4b2f2005-06-27 14:59:41 +0200180 struct hda_pcm pcm_rec[2]; /* PCM information */
181
182 /* dynamic controls and input_mux */
183 struct auto_pin_cfg autocfg;
184 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100185 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200186 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200187 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100188 struct hda_input_mux private_mono_mux;
Takashi Iwai2134ea42008-01-10 16:53:55 +0100189
190 /* virtual master */
191 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +0200192};
193
194static hda_nid_t stac9200_adc_nids[1] = {
195 0x03,
196};
197
198static hda_nid_t stac9200_mux_nids[1] = {
199 0x0c,
200};
201
202static hda_nid_t stac9200_dac_nids[1] = {
203 0x02,
204};
205
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100206static hda_nid_t stac92hd73xx_pwr_nids[8] = {
207 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
208 0x0f, 0x10, 0x11
209};
210
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100211static hda_nid_t stac92hd73xx_adc_nids[2] = {
212 0x1a, 0x1b
213};
214
215#define STAC92HD73XX_NUM_DMICS 2
216static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
217 0x13, 0x14, 0
218};
219
220#define STAC92HD73_DAC_COUNT 5
221static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
222 0x15, 0x16, 0x17, 0x18, 0x19,
223};
224
225static hda_nid_t stac92hd73xx_mux_nids[4] = {
226 0x28, 0x29, 0x2a, 0x2b,
227};
228
229static hda_nid_t stac92hd73xx_dmux_nids[2] = {
230 0x20, 0x21,
231};
232
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100233static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
234 0x0a, 0x0d, 0x0f
235};
236
Matthew Ranostaye035b842007-11-06 11:53:55 +0100237static hda_nid_t stac92hd71bxx_adc_nids[2] = {
238 0x12, 0x13,
239};
240
241static hda_nid_t stac92hd71bxx_mux_nids[2] = {
242 0x1a, 0x1b
243};
244
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100245static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
246 0x1c,
247};
248
Matthew Ranostaye035b842007-11-06 11:53:55 +0100249static hda_nid_t stac92hd71bxx_dac_nids[2] = {
250 0x10, /*0x11, */
251};
252
253#define STAC92HD71BXX_NUM_DMICS 2
254static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
255 0x18, 0x19, 0
256};
257
Tobin Davis8e21c342007-01-08 11:04:17 +0100258static hda_nid_t stac925x_adc_nids[1] = {
259 0x03,
260};
261
262static hda_nid_t stac925x_mux_nids[1] = {
263 0x0f,
264};
265
266static hda_nid_t stac925x_dac_nids[1] = {
267 0x02,
268};
269
Takashi Iwaif6e98522007-10-16 14:27:04 +0200270#define STAC925X_NUM_DMICS 1
271static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
272 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200273};
274
Takashi Iwai1697055e2007-12-18 18:05:52 +0100275static hda_nid_t stac925x_dmux_nids[1] = {
276 0x14,
277};
278
Matt2f2f4252005-04-13 14:45:30 +0200279static hda_nid_t stac922x_adc_nids[2] = {
280 0x06, 0x07,
281};
282
283static hda_nid_t stac922x_mux_nids[2] = {
284 0x12, 0x13,
285};
286
Matt Porter3cc08dc2006-01-23 15:27:49 +0100287static hda_nid_t stac927x_adc_nids[3] = {
288 0x07, 0x08, 0x09
289};
290
291static hda_nid_t stac927x_mux_nids[3] = {
292 0x15, 0x16, 0x17
293};
294
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100295static hda_nid_t stac927x_dac_nids[6] = {
296 0x02, 0x03, 0x04, 0x05, 0x06, 0
297};
298
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100299static hda_nid_t stac927x_dmux_nids[1] = {
300 0x1b,
301};
302
Matthew Ranostay7f168592007-10-18 17:38:17 +0200303#define STAC927X_NUM_DMICS 2
304static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
305 0x13, 0x14, 0
306};
307
Matt Porterf3302a52006-07-31 12:49:34 +0200308static hda_nid_t stac9205_adc_nids[2] = {
309 0x12, 0x13
310};
311
312static hda_nid_t stac9205_mux_nids[2] = {
313 0x19, 0x1a
314};
315
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100316static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100317 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100318};
319
Takashi Iwaif6e98522007-10-16 14:27:04 +0200320#define STAC9205_NUM_DMICS 2
321static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
322 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200323};
324
Mattc7d4b2f2005-06-27 14:59:41 +0200325static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200326 0x08, 0x09, 0x0d, 0x0e,
327 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200328};
329
Tobin Davis8e21c342007-01-08 11:04:17 +0100330static hda_nid_t stac925x_pin_nids[8] = {
331 0x07, 0x08, 0x0a, 0x0b,
332 0x0c, 0x0d, 0x10, 0x11,
333};
334
Matt2f2f4252005-04-13 14:45:30 +0200335static hda_nid_t stac922x_pin_nids[10] = {
336 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
337 0x0f, 0x10, 0x11, 0x15, 0x1b,
338};
339
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100340static hda_nid_t stac92hd73xx_pin_nids[12] = {
341 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
342 0x0f, 0x10, 0x11, 0x12, 0x13,
343 0x14, 0x22
344};
345
Matthew Ranostaye035b842007-11-06 11:53:55 +0100346static hda_nid_t stac92hd71bxx_pin_nids[10] = {
347 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
348 0x0f, 0x14, 0x18, 0x19, 0x1e,
349};
350
Matt Porter3cc08dc2006-01-23 15:27:49 +0100351static hda_nid_t stac927x_pin_nids[14] = {
352 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
353 0x0f, 0x10, 0x11, 0x12, 0x13,
354 0x14, 0x21, 0x22, 0x23,
355};
356
Matt Porterf3302a52006-07-31 12:49:34 +0200357static hda_nid_t stac9205_pin_nids[12] = {
358 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
359 0x0f, 0x14, 0x16, 0x17, 0x18,
360 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200361};
362
Matt Porter8b657272006-10-26 17:12:59 +0200363static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
364 struct snd_ctl_elem_info *uinfo)
365{
366 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
367 struct sigmatel_spec *spec = codec->spec;
368 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
369}
370
371static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_value *ucontrol)
373{
374 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
375 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100376 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200377
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100378 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200379 return 0;
380}
381
382static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
383 struct snd_ctl_elem_value *ucontrol)
384{
385 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
386 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100387 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200388
389 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100390 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200391}
392
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100393static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200394{
395 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
396 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200397 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200398}
399
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100400static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200401{
402 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
403 struct sigmatel_spec *spec = codec->spec;
404 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
405
406 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
407 return 0;
408}
409
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100410static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200411{
412 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
413 struct sigmatel_spec *spec = codec->spec;
414 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
415
Mattc7d4b2f2005-06-27 14:59:41 +0200416 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200417 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
418}
419
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100420static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
421 struct snd_ctl_elem_info *uinfo)
422{
423 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
424 struct sigmatel_spec *spec = codec->spec;
425 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
426}
427
428static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
429 struct snd_ctl_elem_value *ucontrol)
430{
431 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
432 struct sigmatel_spec *spec = codec->spec;
433
434 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
435 return 0;
436}
437
438static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_value *ucontrol)
440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
442 struct sigmatel_spec *spec = codec->spec;
443
444 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
445 spec->mono_nid, &spec->cur_mmux);
446}
447
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200448#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
449
450static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
451 struct snd_ctl_elem_value *ucontrol)
452{
453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100454 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200455 struct sigmatel_spec *spec = codec->spec;
456
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100457 ucontrol->value.integer.value[0] = !!(spec->aloopback &
458 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200459 return 0;
460}
461
462static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_value *ucontrol)
464{
465 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
466 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100467 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200468 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100469 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200470
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100471 idx_val = spec->aloopback_mask << idx;
472 if (ucontrol->value.integer.value[0])
473 val = spec->aloopback | idx_val;
474 else
475 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100476 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200477 return 0;
478
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100479 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200480
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100481 /* Only return the bits defined by the shift value of the
482 * first two bytes of the mask
483 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200484 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100485 kcontrol->private_value & 0xFFFF, 0x0);
486 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200487
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100488 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200489 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100490 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200491 } else {
492 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100493 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200494 }
495
496 snd_hda_codec_write_cache(codec, codec->afg, 0,
497 kcontrol->private_value >> 16, dac_mode);
498
499 return 1;
500}
501
Mattc7d4b2f2005-06-27 14:59:41 +0200502static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200503 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200504 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200505 {}
506};
507
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200508static struct hda_verb stac9200_eapd_init[] = {
509 /* set dac0mux for dac converter */
510 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
511 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
512 {}
513};
514
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100515static struct hda_verb stac92hd73xx_6ch_core_init[] = {
516 /* set master volume and direct control */
517 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
518 /* setup audio connections */
519 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
520 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
521 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
522 /* setup adcs to point to mixer */
523 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
524 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100525 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
526 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
527 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
528 /* setup import muxs */
529 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
530 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
531 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
532 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
533 {}
534};
535
536static struct hda_verb stac92hd73xx_8ch_core_init[] = {
537 /* set master volume and direct control */
538 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
539 /* setup audio connections */
540 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
541 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
542 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
543 /* connect hp ports to dac3 */
544 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
545 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
546 /* setup adcs to point to mixer */
547 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
548 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100549 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
550 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
551 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
552 /* setup import muxs */
553 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
554 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
555 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
556 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
557 {}
558};
559
560static struct hda_verb stac92hd73xx_10ch_core_init[] = {
561 /* set master volume and direct control */
562 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
563 /* setup audio connections */
564 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
565 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
566 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
567 /* dac3 is connected to import3 mux */
568 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
569 /* connect hp ports to dac4 */
570 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
571 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
572 /* setup adcs to point to mixer */
573 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
574 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100575 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
576 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
577 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
578 /* setup import muxs */
579 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
580 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
581 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
582 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
583 {}
584};
585
Matthew Ranostaye035b842007-11-06 11:53:55 +0100586static struct hda_verb stac92hd71bxx_core_init[] = {
587 /* set master volume and direct control */
588 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
589 /* connect headphone jack to dac1 */
590 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100591 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
592 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
593 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
594 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
595 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100596};
597
598static struct hda_verb stac92hd71bxx_analog_core_init[] = {
599 /* set master volume and direct control */
600 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
601 /* connect headphone jack to dac1 */
602 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100603 /* connect ports 0d and 0f to audio mixer */
604 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
605 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100606 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100607 /* unmute dac0 input in audio mixer */
608 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100609 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
610 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
611 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
612 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100613 {}
614};
615
Tobin Davis8e21c342007-01-08 11:04:17 +0100616static struct hda_verb stac925x_core_init[] = {
617 /* set dac0mux for dac converter */
618 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
619 {}
620};
621
Mattc7d4b2f2005-06-27 14:59:41 +0200622static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200623 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200624 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200625 {}
626};
627
Tobin Davis93ed1502006-09-01 21:03:12 +0200628static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200629 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200630 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200631 /* unmute node 0x1b */
632 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
633 /* select node 0x03 as DAC */
634 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
635 {}
636};
637
Matt Porter3cc08dc2006-01-23 15:27:49 +0100638static struct hda_verb stac927x_core_init[] = {
639 /* set master volume and direct control */
640 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
641 {}
642};
643
Matt Porterf3302a52006-07-31 12:49:34 +0200644static struct hda_verb stac9205_core_init[] = {
645 /* set master volume and direct control */
646 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
647 {}
648};
649
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100650#define STAC_MONO_MUX \
651 { \
652 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
653 .name = "Mono Mux", \
654 .count = 1, \
655 .info = stac92xx_mono_mux_enum_info, \
656 .get = stac92xx_mono_mux_enum_get, \
657 .put = stac92xx_mono_mux_enum_put, \
658 }
659
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200660#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200661 { \
662 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
663 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200664 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200665 .info = stac92xx_mux_enum_info, \
666 .get = stac92xx_mux_enum_get, \
667 .put = stac92xx_mux_enum_put, \
668 }
669
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100670#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200671 { \
672 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
673 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100674 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200675 .info = stac92xx_aloopback_info, \
676 .get = stac92xx_aloopback_get, \
677 .put = stac92xx_aloopback_put, \
678 .private_value = verb_read | (verb_write << 16), \
679 }
680
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100681static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200682 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
683 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200684 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200685 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
686 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200687 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200688 { } /* end */
689};
690
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100691static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
693
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100694 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
695 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
696
697 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
698 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
699
700 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
701 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
702
703 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
704 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
705
706 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
707 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
708
709 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
710 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
711
712 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
713 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
714 { } /* end */
715};
716
717static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100718 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
719
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100720 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
721 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
722
723 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
724 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
725
726 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
727 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
728
729 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
730 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
731
732 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
733 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
734
735 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
736 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
737
738 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
739 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
740 { } /* end */
741};
742
743static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100744 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
745
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100746 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
747 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
748
749 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
750 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
751
752 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
753 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
754
755 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
756 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
757
758 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
759 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
760
761 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
762 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
763
764 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
765 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
766 { } /* end */
767};
768
Matthew Ranostay541eee82007-12-14 12:08:04 +0100769static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100770 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100771
Matthew Ranostay9b359472007-11-07 13:03:12 +0100772 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
773 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
774 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
775
776 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
777 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
778 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
779
780 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
781 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100782 { } /* end */
783};
784
Matthew Ranostay541eee82007-12-14 12:08:04 +0100785static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100786 STAC_INPUT_SOURCE(2),
787 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
788
Matthew Ranostay541eee82007-12-14 12:08:04 +0100789 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
790 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
791 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
792
793 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
794 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
795 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
796 { } /* end */
797};
798
Tobin Davis8e21c342007-01-08 11:04:17 +0100799static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200800 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100801 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
802 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
803 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
804 { } /* end */
805};
806
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100807static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200808 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100809 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200810
811 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
812 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
813 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
814
815 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
816 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
817 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
818
819 { } /* end */
820};
821
822/* This needs to be generated dynamically based on sequence */
823static struct snd_kcontrol_new stac922x_mixer[] = {
824 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200825 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
826 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
827 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
828
829 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
830 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
831 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
832 { } /* end */
833};
834
835
836static struct snd_kcontrol_new stac927x_mixer[] = {
837 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100838 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200839
840 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
841 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
842 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
843
844 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
845 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
846 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
847
848 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
849 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
850 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200851 { } /* end */
852};
853
Takashi Iwai1697055e2007-12-18 18:05:52 +0100854static struct snd_kcontrol_new stac_dmux_mixer = {
855 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
856 .name = "Digital Input Source",
857 /* count set later */
858 .info = stac92xx_dmux_enum_info,
859 .get = stac92xx_dmux_enum_get,
860 .put = stac92xx_dmux_enum_put,
861};
862
Takashi Iwai2134ea42008-01-10 16:53:55 +0100863static const char *slave_vols[] = {
864 "Front Playback Volume",
865 "Surround Playback Volume",
866 "Center Playback Volume",
867 "LFE Playback Volume",
868 "Side Playback Volume",
869 "Headphone Playback Volume",
870 "Headphone Playback Volume",
871 "Speaker Playback Volume",
872 "External Speaker Playback Volume",
873 "Speaker2 Playback Volume",
874 NULL
875};
876
877static const char *slave_sws[] = {
878 "Front Playback Switch",
879 "Surround Playback Switch",
880 "Center Playback Switch",
881 "LFE Playback Switch",
882 "Side Playback Switch",
883 "Headphone Playback Switch",
884 "Headphone Playback Switch",
885 "Speaker Playback Switch",
886 "External Speaker Playback Switch",
887 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100888 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100889 NULL
890};
891
Matt2f2f4252005-04-13 14:45:30 +0200892static int stac92xx_build_controls(struct hda_codec *codec)
893{
894 struct sigmatel_spec *spec = codec->spec;
895 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200896 int i;
Matt2f2f4252005-04-13 14:45:30 +0200897
898 err = snd_hda_add_new_ctls(codec, spec->mixer);
899 if (err < 0)
900 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200901
902 for (i = 0; i < spec->num_mixers; i++) {
903 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
904 if (err < 0)
905 return err;
906 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100907 if (spec->num_dmuxes > 0) {
908 stac_dmux_mixer.count = spec->num_dmuxes;
909 err = snd_ctl_add(codec->bus->card,
910 snd_ctl_new1(&stac_dmux_mixer, codec));
911 if (err < 0)
912 return err;
913 }
Mattc7d4b2f2005-06-27 14:59:41 +0200914
Mattdabbed62005-06-14 10:19:34 +0200915 if (spec->multiout.dig_out_nid) {
916 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
917 if (err < 0)
918 return err;
919 }
920 if (spec->dig_in_nid) {
921 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
922 if (err < 0)
923 return err;
924 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100925
926 /* if we have no master control, let's create it */
927 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
928 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
929 HDA_OUTPUT, spec->vmaster_tlv);
930 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
931 spec->vmaster_tlv, slave_vols);
932 if (err < 0)
933 return err;
934 }
935 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
936 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
937 NULL, slave_sws);
938 if (err < 0)
939 return err;
940 }
941
Mattdabbed62005-06-14 10:19:34 +0200942 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200943}
944
Matt Porter403d1942005-11-29 15:00:51 +0100945static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200946 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200947 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
948};
949
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200950/*
951 STAC 9200 pin configs for
952 102801A8
953 102801DE
954 102801E8
955*/
956static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200957 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
958 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200959};
960
961/*
962 STAC 9200 pin configs for
963 102801C0
964 102801C1
965*/
966static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200967 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
968 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200969};
970
971/*
972 STAC 9200 pin configs for
973 102801C4 (Dell Dimension E310)
974 102801C5
975 102801C7
976 102801D9
977 102801DA
978 102801E3
979*/
980static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200981 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
982 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200983};
984
985
986/*
987 STAC 9200-32 pin configs for
988 102801B5 (Dell Inspiron 630m)
989 102801D8 (Dell Inspiron 640m)
990*/
991static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200992 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
993 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200994};
995
996/*
997 STAC 9200-32 pin configs for
998 102801C2 (Dell Latitude D620)
999 102801C8
1000 102801CC (Dell Latitude D820)
1001 102801D4
1002 102801D6
1003*/
1004static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001005 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1006 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001007};
1008
1009/*
1010 STAC 9200-32 pin configs for
1011 102801CE (Dell XPS M1710)
1012 102801CF (Dell Precision M90)
1013*/
1014static unsigned int dell9200_m23_pin_configs[8] = {
1015 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1016 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1017};
1018
1019/*
1020 STAC 9200-32 pin configs for
1021 102801C9
1022 102801CA
1023 102801CB (Dell Latitude 120L)
1024 102801D3
1025*/
1026static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001027 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1028 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001029};
1030
1031/*
1032 STAC 9200-32 pin configs for
1033 102801BD (Dell Inspiron E1505n)
1034 102801EE
1035 102801EF
1036*/
1037static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001038 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1039 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001040};
1041
1042/*
1043 STAC 9200-32 pin configs for
1044 102801F5 (Dell Inspiron 1501)
1045 102801F6
1046*/
1047static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001048 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1049 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001050};
1051
1052/*
1053 STAC 9200-32
1054 102801CD (Dell Inspiron E1705/9400)
1055*/
1056static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001057 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1058 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001059};
1060
Tobin Davisbf277782008-02-03 20:31:47 +01001061static unsigned int oqo9200_pin_configs[8] = {
1062 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1063 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1064};
1065
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001066
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001067static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1068 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001069 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001070 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1071 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1072 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1073 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1074 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1075 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1076 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1077 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1078 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1079 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001080};
1081
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001082static const char *stac9200_models[STAC_9200_MODELS] = {
1083 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001084 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001085 [STAC_9200_DELL_D21] = "dell-d21",
1086 [STAC_9200_DELL_D22] = "dell-d22",
1087 [STAC_9200_DELL_D23] = "dell-d23",
1088 [STAC_9200_DELL_M21] = "dell-m21",
1089 [STAC_9200_DELL_M22] = "dell-m22",
1090 [STAC_9200_DELL_M23] = "dell-m23",
1091 [STAC_9200_DELL_M24] = "dell-m24",
1092 [STAC_9200_DELL_M25] = "dell-m25",
1093 [STAC_9200_DELL_M26] = "dell-m26",
1094 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001095 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001096};
1097
1098static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1099 /* SigmaTel reference board */
1100 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1101 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001102 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001103 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1104 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001105 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001106 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1107 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1108 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1109 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1110 "unknown Dell", STAC_9200_DELL_D22),
1111 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1112 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001113 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001114 "Dell Latitude D620", STAC_9200_DELL_M22),
1115 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1116 "unknown Dell", STAC_9200_DELL_D23),
1117 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1118 "unknown Dell", STAC_9200_DELL_D23),
1119 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1120 "unknown Dell", STAC_9200_DELL_M22),
1121 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1122 "unknown Dell", STAC_9200_DELL_M24),
1123 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1124 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001125 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001126 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001127 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001128 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001129 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001130 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001131 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001132 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001133 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001134 "Dell Precision M90", STAC_9200_DELL_M23),
1135 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1136 "unknown Dell", STAC_9200_DELL_M22),
1137 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1138 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001139 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001140 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001141 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001142 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1143 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1144 "unknown Dell", STAC_9200_DELL_D23),
1145 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1146 "unknown Dell", STAC_9200_DELL_D23),
1147 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1148 "unknown Dell", STAC_9200_DELL_D21),
1149 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1150 "unknown Dell", STAC_9200_DELL_D23),
1151 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1152 "unknown Dell", STAC_9200_DELL_D21),
1153 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1154 "unknown Dell", STAC_9200_DELL_M25),
1155 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1156 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001157 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001158 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1159 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1160 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001161 /* Panasonic */
1162 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001163 /* Gateway machines needs EAPD to be set on resume */
1164 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1165 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1166 STAC_9200_GATEWAY),
1167 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1168 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001169 /* OQO Mobile */
1170 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001171 {} /* terminator */
1172};
1173
Tobin Davis8e21c342007-01-08 11:04:17 +01001174static unsigned int ref925x_pin_configs[8] = {
1175 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001176 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001177};
1178
1179static unsigned int stac925x_MA6_pin_configs[8] = {
1180 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1181 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1182};
1183
Tobin Davis2c11f952007-05-17 09:36:34 +02001184static unsigned int stac925x_PA6_pin_configs[8] = {
1185 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1186 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1187};
1188
Tobin Davis8e21c342007-01-08 11:04:17 +01001189static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001190 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1191 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001192};
1193
1194static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1195 [STAC_REF] = ref925x_pin_configs,
1196 [STAC_M2_2] = stac925xM2_2_pin_configs,
1197 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001198 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001199};
1200
1201static const char *stac925x_models[STAC_925x_MODELS] = {
1202 [STAC_REF] = "ref",
1203 [STAC_M2_2] = "m2-2",
1204 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001205 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001206};
1207
1208static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1209 /* SigmaTel reference board */
1210 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001211 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001212 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1213 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1214 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001215 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001216 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1217 {} /* terminator */
1218};
1219
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001220static unsigned int ref92hd73xx_pin_configs[12] = {
1221 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1222 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1223 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1224};
1225
1226static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1227 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1228};
1229
1230static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1231 [STAC_92HD73XX_REF] = "ref",
1232};
1233
1234static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1235 /* SigmaTel reference board */
1236 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1237 "DFI LanParty", STAC_92HD73XX_REF),
1238 {} /* terminator */
1239};
1240
Matthew Ranostaye035b842007-11-06 11:53:55 +01001241static unsigned int ref92hd71bxx_pin_configs[10] = {
1242 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001243 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001244 0x90a000f0, 0x01452050,
1245};
1246
1247static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1248 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1249};
1250
1251static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1252 [STAC_92HD71BXX_REF] = "ref",
1253};
1254
1255static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1256 /* SigmaTel reference board */
1257 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1258 "DFI LanParty", STAC_92HD71BXX_REF),
1259 {} /* terminator */
1260};
1261
Matt Porter403d1942005-11-29 15:00:51 +01001262static unsigned int ref922x_pin_configs[10] = {
1263 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1264 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001265 0x40000100, 0x40000100,
1266};
1267
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001268/*
1269 STAC 922X pin configs for
1270 102801A7
1271 102801AB
1272 102801A9
1273 102801D1
1274 102801D2
1275*/
1276static unsigned int dell_922x_d81_pin_configs[10] = {
1277 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1278 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1279 0x01813122, 0x400001f2,
1280};
1281
1282/*
1283 STAC 922X pin configs for
1284 102801AC
1285 102801D0
1286*/
1287static unsigned int dell_922x_d82_pin_configs[10] = {
1288 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1289 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1290 0x01813122, 0x400001f1,
1291};
1292
1293/*
1294 STAC 922X pin configs for
1295 102801BF
1296*/
1297static unsigned int dell_922x_m81_pin_configs[10] = {
1298 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1299 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1300 0x40C003f1, 0x405003f0,
1301};
1302
1303/*
1304 STAC 9221 A1 pin configs for
1305 102801D7 (Dell XPS M1210)
1306*/
1307static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001308 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1309 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001310 0x508003f3, 0x405003f4,
1311};
1312
Matt Porter403d1942005-11-29 15:00:51 +01001313static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001314 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001315 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1316 0x02a19120, 0x40000100,
1317};
1318
1319static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001320 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1321 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001322 0x02a19320, 0x40000100,
1323};
1324
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001325static unsigned int intel_mac_v1_pin_configs[10] = {
1326 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1327 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001328 0x400000fc, 0x400000fb,
1329};
1330
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001331static unsigned int intel_mac_v2_pin_configs[10] = {
1332 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1333 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001334 0x400000fc, 0x400000fb,
1335};
1336
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001337static unsigned int intel_mac_v3_pin_configs[10] = {
1338 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1339 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1340 0x400000fc, 0x400000fb,
1341};
1342
1343static unsigned int intel_mac_v4_pin_configs[10] = {
1344 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1345 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1346 0x400000fc, 0x400000fb,
1347};
1348
1349static unsigned int intel_mac_v5_pin_configs[10] = {
1350 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1351 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1352 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001353};
1354
Takashi Iwai76c08822007-06-19 12:17:42 +02001355
Takashi Iwai19039bd2006-06-28 15:52:16 +02001356static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001357 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001358 [STAC_D945GTP3] = d945gtp3_pin_configs,
1359 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001360 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1361 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1362 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1363 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1364 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001365 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001366 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1367 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1368 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1369 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1370 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1371 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001372 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1373 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1374 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1375 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001376};
1377
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001378static const char *stac922x_models[STAC_922X_MODELS] = {
1379 [STAC_D945_REF] = "ref",
1380 [STAC_D945GTP5] = "5stack",
1381 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001382 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1383 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1384 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1385 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1386 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001387 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001388 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001389 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001390 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1391 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001392 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001393 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001394 [STAC_922X_DELL_D81] = "dell-d81",
1395 [STAC_922X_DELL_D82] = "dell-d82",
1396 [STAC_922X_DELL_M81] = "dell-m81",
1397 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001398};
1399
1400static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1401 /* SigmaTel reference board */
1402 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1403 "DFI LanParty", STAC_D945_REF),
1404 /* Intel 945G based systems */
1405 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1406 "Intel D945G", STAC_D945GTP3),
1407 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1408 "Intel D945G", STAC_D945GTP3),
1409 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1410 "Intel D945G", STAC_D945GTP3),
1411 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1412 "Intel D945G", STAC_D945GTP3),
1413 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1414 "Intel D945G", STAC_D945GTP3),
1415 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1416 "Intel D945G", STAC_D945GTP3),
1417 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1418 "Intel D945G", STAC_D945GTP3),
1419 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1420 "Intel D945G", STAC_D945GTP3),
1421 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1422 "Intel D945G", STAC_D945GTP3),
1423 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1424 "Intel D945G", STAC_D945GTP3),
1425 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1426 "Intel D945G", STAC_D945GTP3),
1427 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1428 "Intel D945G", STAC_D945GTP3),
1429 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1430 "Intel D945G", STAC_D945GTP3),
1431 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1432 "Intel D945G", STAC_D945GTP3),
1433 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1434 "Intel D945G", STAC_D945GTP3),
1435 /* Intel D945G 5-stack systems */
1436 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1437 "Intel D945G", STAC_D945GTP5),
1438 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1439 "Intel D945G", STAC_D945GTP5),
1440 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1441 "Intel D945G", STAC_D945GTP5),
1442 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1443 "Intel D945G", STAC_D945GTP5),
1444 /* Intel 945P based systems */
1445 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1446 "Intel D945P", STAC_D945GTP3),
1447 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1448 "Intel D945P", STAC_D945GTP3),
1449 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1450 "Intel D945P", STAC_D945GTP3),
1451 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1452 "Intel D945P", STAC_D945GTP3),
1453 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1454 "Intel D945P", STAC_D945GTP3),
1455 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1456 "Intel D945P", STAC_D945GTP5),
1457 /* other systems */
1458 /* Apple Mac Mini (early 2006) */
1459 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001460 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001461 /* Dell systems */
1462 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1463 "unknown Dell", STAC_922X_DELL_D81),
1464 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1465 "unknown Dell", STAC_922X_DELL_D81),
1466 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1467 "unknown Dell", STAC_922X_DELL_D81),
1468 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1469 "unknown Dell", STAC_922X_DELL_D82),
1470 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1471 "unknown Dell", STAC_922X_DELL_M81),
1472 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1473 "unknown Dell", STAC_922X_DELL_D82),
1474 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1475 "unknown Dell", STAC_922X_DELL_D81),
1476 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1477 "unknown Dell", STAC_922X_DELL_D81),
1478 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1479 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001480 {} /* terminator */
1481};
1482
Matt Porter3cc08dc2006-01-23 15:27:49 +01001483static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001484 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1485 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1486 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1487 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001488};
1489
Tobin Davis93ed1502006-09-01 21:03:12 +02001490static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001491 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1492 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1493 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1494 0x40000100, 0x40000100
1495};
1496
Tobin Davis93ed1502006-09-01 21:03:12 +02001497static unsigned int d965_5st_pin_configs[14] = {
1498 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1499 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1500 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1501 0x40000100, 0x40000100
1502};
1503
Tobin Davis4ff076e2007-08-07 11:48:12 +02001504static unsigned int dell_3st_pin_configs[14] = {
1505 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1506 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001507 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001508 0x40c003fc, 0x40000100
1509};
1510
Tobin Davis93ed1502006-09-01 21:03:12 +02001511static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001512 [STAC_D965_REF] = ref927x_pin_configs,
1513 [STAC_D965_3ST] = d965_3st_pin_configs,
1514 [STAC_D965_5ST] = d965_5st_pin_configs,
1515 [STAC_DELL_3ST] = dell_3st_pin_configs,
1516 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001517};
1518
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001519static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001520 [STAC_D965_REF] = "ref",
1521 [STAC_D965_3ST] = "3stack",
1522 [STAC_D965_5ST] = "5stack",
1523 [STAC_DELL_3ST] = "dell-3stack",
1524 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001525};
1526
1527static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1528 /* SigmaTel reference board */
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1530 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001531 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001532 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001534 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001551 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001552 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001553 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001554 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001556 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001557 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001559 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1560 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1561 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1563 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1564 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001565 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001566 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1567 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1569 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1570 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1571 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1572 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1573 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001575 {} /* terminator */
1576};
1577
Matt Porterf3302a52006-07-31 12:49:34 +02001578static unsigned int ref9205_pin_configs[12] = {
1579 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001580 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001581 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001582};
1583
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001584/*
1585 STAC 9205 pin configs for
1586 102801F1
1587 102801F2
1588 102801FC
1589 102801FD
1590 10280204
1591 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001592 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001593*/
1594static unsigned int dell_9205_m42_pin_configs[12] = {
1595 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1596 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1597 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1598};
1599
1600/*
1601 STAC 9205 pin configs for
1602 102801F9
1603 102801FA
1604 102801FE
1605 102801FF (Dell Precision M4300)
1606 10280206
1607 10280200
1608 10280201
1609*/
1610static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001611 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1612 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1613 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1614};
1615
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001616static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001617 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1618 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1619 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1620};
1621
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001622static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001623 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001624 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1625 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1626 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001627};
1628
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001629static const char *stac9205_models[STAC_9205_MODELS] = {
1630 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001631 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001632 [STAC_9205_DELL_M43] = "dell-m43",
1633 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001634};
1635
1636static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1637 /* SigmaTel reference board */
1638 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1639 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001640 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1641 "unknown Dell", STAC_9205_DELL_M42),
1642 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1643 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001644 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001645 "Dell Precision", STAC_9205_DELL_M43),
1646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1647 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1649 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001650 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1651 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001652 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1653 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001654 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1655 "unknown Dell", STAC_9205_DELL_M42),
1656 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1657 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001658 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1659 "Dell Precision", STAC_9205_DELL_M43),
1660 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001661 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001662 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1663 "Dell Precision", STAC_9205_DELL_M43),
1664 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1665 "Dell Inspiron", STAC_9205_DELL_M44),
1666 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1667 "Dell Inspiron", STAC_9205_DELL_M44),
1668 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1669 "Dell Inspiron", STAC_9205_DELL_M44),
1670 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1671 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001672 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1673 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001674 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1675 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001676 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1677 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001678 {} /* terminator */
1679};
1680
Richard Fish11b44bb2006-08-23 18:31:34 +02001681static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1682{
1683 int i;
1684 struct sigmatel_spec *spec = codec->spec;
1685
1686 if (! spec->bios_pin_configs) {
1687 spec->bios_pin_configs = kcalloc(spec->num_pins,
1688 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1689 if (! spec->bios_pin_configs)
1690 return -ENOMEM;
1691 }
1692
1693 for (i = 0; i < spec->num_pins; i++) {
1694 hda_nid_t nid = spec->pin_nids[i];
1695 unsigned int pin_cfg;
1696
1697 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1698 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1699 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1700 nid, pin_cfg);
1701 spec->bios_pin_configs[i] = pin_cfg;
1702 }
1703
1704 return 0;
1705}
1706
Matthew Ranostay87d48362007-07-17 11:52:24 +02001707static void stac92xx_set_config_reg(struct hda_codec *codec,
1708 hda_nid_t pin_nid, unsigned int pin_config)
1709{
1710 int i;
1711 snd_hda_codec_write(codec, pin_nid, 0,
1712 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1713 pin_config & 0x000000ff);
1714 snd_hda_codec_write(codec, pin_nid, 0,
1715 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1716 (pin_config & 0x0000ff00) >> 8);
1717 snd_hda_codec_write(codec, pin_nid, 0,
1718 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1719 (pin_config & 0x00ff0000) >> 16);
1720 snd_hda_codec_write(codec, pin_nid, 0,
1721 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1722 pin_config >> 24);
1723 i = snd_hda_codec_read(codec, pin_nid, 0,
1724 AC_VERB_GET_CONFIG_DEFAULT,
1725 0x00);
1726 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1727 pin_nid, i);
1728}
1729
Matt2f2f4252005-04-13 14:45:30 +02001730static void stac92xx_set_config_regs(struct hda_codec *codec)
1731{
1732 int i;
1733 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001734
Matthew Ranostay87d48362007-07-17 11:52:24 +02001735 if (!spec->pin_configs)
1736 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001737
Matthew Ranostay87d48362007-07-17 11:52:24 +02001738 for (i = 0; i < spec->num_pins; i++)
1739 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1740 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001741}
Matt2f2f4252005-04-13 14:45:30 +02001742
Matt2f2f4252005-04-13 14:45:30 +02001743/*
1744 * Analog playback callbacks
1745 */
1746static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1747 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001748 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001749{
1750 struct sigmatel_spec *spec = codec->spec;
1751 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1752}
1753
1754static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1755 struct hda_codec *codec,
1756 unsigned int stream_tag,
1757 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001758 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001759{
1760 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001761 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001762}
1763
1764static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1765 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001766 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001767{
1768 struct sigmatel_spec *spec = codec->spec;
1769 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1770}
1771
1772/*
Mattdabbed62005-06-14 10:19:34 +02001773 * Digital playback callbacks
1774 */
1775static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1776 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001777 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001778{
1779 struct sigmatel_spec *spec = codec->spec;
1780 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1781}
1782
1783static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1784 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001785 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001786{
1787 struct sigmatel_spec *spec = codec->spec;
1788 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1789}
1790
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001791static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1792 struct hda_codec *codec,
1793 unsigned int stream_tag,
1794 unsigned int format,
1795 struct snd_pcm_substream *substream)
1796{
1797 struct sigmatel_spec *spec = codec->spec;
1798 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1799 stream_tag, format, substream);
1800}
1801
Mattdabbed62005-06-14 10:19:34 +02001802
1803/*
Matt2f2f4252005-04-13 14:45:30 +02001804 * Analog capture callbacks
1805 */
1806static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1807 struct hda_codec *codec,
1808 unsigned int stream_tag,
1809 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001810 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001811{
1812 struct sigmatel_spec *spec = codec->spec;
1813
1814 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1815 stream_tag, 0, format);
1816 return 0;
1817}
1818
1819static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1820 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001821 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001822{
1823 struct sigmatel_spec *spec = codec->spec;
1824
1825 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1826 return 0;
1827}
1828
Mattdabbed62005-06-14 10:19:34 +02001829static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1830 .substreams = 1,
1831 .channels_min = 2,
1832 .channels_max = 2,
1833 /* NID is set in stac92xx_build_pcms */
1834 .ops = {
1835 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001836 .close = stac92xx_dig_playback_pcm_close,
1837 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001838 },
1839};
1840
1841static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1842 .substreams = 1,
1843 .channels_min = 2,
1844 .channels_max = 2,
1845 /* NID is set in stac92xx_build_pcms */
1846};
1847
Matt2f2f4252005-04-13 14:45:30 +02001848static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1849 .substreams = 1,
1850 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001851 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001852 .nid = 0x02, /* NID to query formats and rates */
1853 .ops = {
1854 .open = stac92xx_playback_pcm_open,
1855 .prepare = stac92xx_playback_pcm_prepare,
1856 .cleanup = stac92xx_playback_pcm_cleanup
1857 },
1858};
1859
Matt Porter3cc08dc2006-01-23 15:27:49 +01001860static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1861 .substreams = 1,
1862 .channels_min = 2,
1863 .channels_max = 2,
1864 .nid = 0x06, /* NID to query formats and rates */
1865 .ops = {
1866 .open = stac92xx_playback_pcm_open,
1867 .prepare = stac92xx_playback_pcm_prepare,
1868 .cleanup = stac92xx_playback_pcm_cleanup
1869 },
1870};
1871
Matt2f2f4252005-04-13 14:45:30 +02001872static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001873 .channels_min = 2,
1874 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001875 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001876 .ops = {
1877 .prepare = stac92xx_capture_pcm_prepare,
1878 .cleanup = stac92xx_capture_pcm_cleanup
1879 },
1880};
1881
1882static int stac92xx_build_pcms(struct hda_codec *codec)
1883{
1884 struct sigmatel_spec *spec = codec->spec;
1885 struct hda_pcm *info = spec->pcm_rec;
1886
1887 codec->num_pcms = 1;
1888 codec->pcm_info = info;
1889
Mattc7d4b2f2005-06-27 14:59:41 +02001890 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001891 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001892 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001893 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001894 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001895
1896 if (spec->alt_switch) {
1897 codec->num_pcms++;
1898 info++;
1899 info->name = "STAC92xx Analog Alt";
1900 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1901 }
Matt2f2f4252005-04-13 14:45:30 +02001902
Mattdabbed62005-06-14 10:19:34 +02001903 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1904 codec->num_pcms++;
1905 info++;
1906 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001907 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02001908 if (spec->multiout.dig_out_nid) {
1909 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1910 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1911 }
1912 if (spec->dig_in_nid) {
1913 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1914 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1915 }
1916 }
1917
Matt2f2f4252005-04-13 14:45:30 +02001918 return 0;
1919}
1920
Takashi Iwaic960a032006-03-23 17:06:28 +01001921static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1922{
1923 unsigned int pincap = snd_hda_param_read(codec, nid,
1924 AC_PAR_PIN_CAP);
1925 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1926 if (pincap & AC_PINCAP_VREF_100)
1927 return AC_PINCTL_VREF_100;
1928 if (pincap & AC_PINCAP_VREF_80)
1929 return AC_PINCTL_VREF_80;
1930 if (pincap & AC_PINCAP_VREF_50)
1931 return AC_PINCTL_VREF_50;
1932 if (pincap & AC_PINCAP_VREF_GRD)
1933 return AC_PINCTL_VREF_GRD;
1934 return 0;
1935}
1936
Matt Porter403d1942005-11-29 15:00:51 +01001937static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1938
1939{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001940 snd_hda_codec_write_cache(codec, nid, 0,
1941 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001942}
1943
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001944#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001945
1946static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1947{
1948 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1949 struct sigmatel_spec *spec = codec->spec;
1950 int io_idx = kcontrol-> private_value & 0xff;
1951
1952 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1953 return 0;
1954}
1955
1956static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1957{
1958 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1959 struct sigmatel_spec *spec = codec->spec;
1960 hda_nid_t nid = kcontrol->private_value >> 8;
1961 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001962 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001963
1964 spec->io_switch[io_idx] = val;
1965
1966 if (val)
1967 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001968 else {
1969 unsigned int pinctl = AC_PINCTL_IN_EN;
1970 if (io_idx) /* set VREF for mic */
1971 pinctl |= stac92xx_get_vref(codec, nid);
1972 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1973 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001974
1975 /* check the auto-mute again: we need to mute/unmute the speaker
1976 * appropriately according to the pin direction
1977 */
1978 if (spec->hp_detect)
1979 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1980
Matt Porter403d1942005-11-29 15:00:51 +01001981 return 1;
1982}
1983
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001984#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1985
1986static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1987 struct snd_ctl_elem_value *ucontrol)
1988{
1989 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1990 struct sigmatel_spec *spec = codec->spec;
1991
1992 ucontrol->value.integer.value[0] = spec->clfe_swap;
1993 return 0;
1994}
1995
1996static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
1997 struct snd_ctl_elem_value *ucontrol)
1998{
1999 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2000 struct sigmatel_spec *spec = codec->spec;
2001 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002002 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002003
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002004 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002005 return 0;
2006
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002007 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002008
2009 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2010 spec->clfe_swap ? 0x4 : 0x0);
2011
2012 return 1;
2013}
2014
Matt Porter403d1942005-11-29 15:00:51 +01002015#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2016 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2017 .name = xname, \
2018 .index = 0, \
2019 .info = stac92xx_io_switch_info, \
2020 .get = stac92xx_io_switch_get, \
2021 .put = stac92xx_io_switch_put, \
2022 .private_value = xpval, \
2023 }
2024
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002025#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2026 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2027 .name = xname, \
2028 .index = 0, \
2029 .info = stac92xx_clfe_switch_info, \
2030 .get = stac92xx_clfe_switch_get, \
2031 .put = stac92xx_clfe_switch_put, \
2032 .private_value = xpval, \
2033 }
Matt Porter403d1942005-11-29 15:00:51 +01002034
Mattc7d4b2f2005-06-27 14:59:41 +02002035enum {
2036 STAC_CTL_WIDGET_VOL,
2037 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002038 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002039 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002040 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002041};
2042
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002043static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002044 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2045 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002046 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002047 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002048 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002049};
2050
2051/* add dynamic controls */
2052static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2053{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002054 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002055
2056 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2057 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2058
2059 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2060 if (! knew)
2061 return -ENOMEM;
2062 if (spec->kctl_alloc) {
2063 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2064 kfree(spec->kctl_alloc);
2065 }
2066 spec->kctl_alloc = knew;
2067 spec->num_kctl_alloc = num;
2068 }
2069
2070 knew = &spec->kctl_alloc[spec->num_kctl_used];
2071 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002072 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002073 if (! knew->name)
2074 return -ENOMEM;
2075 knew->private_value = val;
2076 spec->num_kctl_used++;
2077 return 0;
2078}
2079
Matt Porter403d1942005-11-29 15:00:51 +01002080/* flag inputs as additional dynamic lineouts */
2081static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2082{
2083 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002084 unsigned int wcaps, wtype;
2085 int i, num_dacs = 0;
2086
2087 /* use the wcaps cache to count all DACs available for line-outs */
2088 for (i = 0; i < codec->num_nodes; i++) {
2089 wcaps = codec->wcaps[i];
2090 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002091
Steve Longerbeam7b043892007-05-03 20:50:03 +02002092 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2093 num_dacs++;
2094 }
Matt Porter403d1942005-11-29 15:00:51 +01002095
Steve Longerbeam7b043892007-05-03 20:50:03 +02002096 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2097
Matt Porter403d1942005-11-29 15:00:51 +01002098 switch (cfg->line_outs) {
2099 case 3:
2100 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002101 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002102 cfg->line_out_pins[cfg->line_outs] =
2103 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002104 spec->line_switch = 1;
2105 cfg->line_outs++;
2106 }
2107 break;
2108 case 2:
2109 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002110 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002111 cfg->line_out_pins[cfg->line_outs] =
2112 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002113 spec->line_switch = 1;
2114 cfg->line_outs++;
2115 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002116 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002117 cfg->line_out_pins[cfg->line_outs] =
2118 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002119 spec->mic_switch = 1;
2120 cfg->line_outs++;
2121 }
2122 break;
2123 case 1:
2124 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002125 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002126 cfg->line_out_pins[cfg->line_outs] =
2127 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002128 spec->line_switch = 1;
2129 cfg->line_outs++;
2130 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002131 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002132 cfg->line_out_pins[cfg->line_outs] =
2133 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002134 spec->mic_switch = 1;
2135 cfg->line_outs++;
2136 }
2137 break;
2138 }
2139
2140 return 0;
2141}
2142
Steve Longerbeam7b043892007-05-03 20:50:03 +02002143
2144static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2145{
2146 int i;
2147
2148 for (i = 0; i < spec->multiout.num_dacs; i++) {
2149 if (spec->multiout.dac_nids[i] == nid)
2150 return 1;
2151 }
2152
2153 return 0;
2154}
2155
Matt Porter3cc08dc2006-01-23 15:27:49 +01002156/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002157 * Fill in the dac_nids table from the parsed pin configuration
2158 * This function only works when every pin in line_out_pins[]
2159 * contains atleast one DAC in its connection list. Some 92xx
2160 * codecs are not connected directly to a DAC, such as the 9200
2161 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002162 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002163static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002164 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002165{
2166 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002167 int i, j, conn_len = 0;
2168 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2169 unsigned int wcaps, wtype;
2170
Mattc7d4b2f2005-06-27 14:59:41 +02002171 for (i = 0; i < cfg->line_outs; i++) {
2172 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002173 conn_len = snd_hda_get_connections(codec, nid, conn,
2174 HDA_MAX_CONNECTIONS);
2175 for (j = 0; j < conn_len; j++) {
2176 wcaps = snd_hda_param_read(codec, conn[j],
2177 AC_PAR_AUDIO_WIDGET_CAP);
2178 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002179 if (wtype != AC_WID_AUD_OUT ||
2180 (wcaps & AC_WCAP_DIGITAL))
2181 continue;
2182 /* conn[j] is a DAC routed to this line-out */
2183 if (!is_in_dac_nids(spec, conn[j]))
2184 break;
2185 }
2186
2187 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002188 if (spec->multiout.num_dacs > 0) {
2189 /* we have already working output pins,
2190 * so let's drop the broken ones again
2191 */
2192 cfg->line_outs = spec->multiout.num_dacs;
2193 break;
2194 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002195 /* error out, no available DAC found */
2196 snd_printk(KERN_ERR
2197 "%s: No available DAC for pin 0x%x\n",
2198 __func__, nid);
2199 return -ENODEV;
2200 }
2201
2202 spec->multiout.dac_nids[i] = conn[j];
2203 spec->multiout.num_dacs++;
2204 if (conn_len > 1) {
2205 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002206 snd_hda_codec_write_cache(codec, nid, 0,
2207 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002208
2209 }
Mattc7d4b2f2005-06-27 14:59:41 +02002210 }
2211
Steve Longerbeam7b043892007-05-03 20:50:03 +02002212 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2213 spec->multiout.num_dacs,
2214 spec->multiout.dac_nids[0],
2215 spec->multiout.dac_nids[1],
2216 spec->multiout.dac_nids[2],
2217 spec->multiout.dac_nids[3],
2218 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002219 return 0;
2220}
2221
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002222/* create volume control/switch for the given prefx type */
2223static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2224{
2225 char name[32];
2226 int err;
2227
2228 sprintf(name, "%s Playback Volume", pfx);
2229 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2230 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2231 if (err < 0)
2232 return err;
2233 sprintf(name, "%s Playback Switch", pfx);
2234 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2235 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2236 if (err < 0)
2237 return err;
2238 return 0;
2239}
2240
Mattc7d4b2f2005-06-27 14:59:41 +02002241/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002242static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002243 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002244{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002245 static const char *chname[4] = {
2246 "Front", "Surround", NULL /*CLFE*/, "Side"
2247 };
Mattc7d4b2f2005-06-27 14:59:41 +02002248 hda_nid_t nid;
2249 int i, err;
2250
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002251 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002252 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002253
2254
Mattc7d4b2f2005-06-27 14:59:41 +02002255 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002256 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002257 continue;
2258
2259 nid = spec->multiout.dac_nids[i];
2260
2261 if (i == 2) {
2262 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002263 err = create_controls(spec, "Center", nid, 1);
2264 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002265 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002266 err = create_controls(spec, "LFE", nid, 2);
2267 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002268 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002269
2270 wid_caps = get_wcaps(codec, nid);
2271
2272 if (wid_caps & AC_WCAP_LR_SWAP) {
2273 err = stac92xx_add_control(spec,
2274 STAC_CTL_WIDGET_CLFE_SWITCH,
2275 "Swap Center/LFE Playback Switch", nid);
2276
2277 if (err < 0)
2278 return err;
2279 }
2280
Mattc7d4b2f2005-06-27 14:59:41 +02002281 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002282 err = create_controls(spec, chname[i], nid, 3);
2283 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002284 return err;
2285 }
2286 }
2287
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002288 if (spec->line_switch) {
2289 nid = cfg->input_pins[AUTO_PIN_LINE];
2290 pincap = snd_hda_param_read(codec, nid,
2291 AC_PAR_PIN_CAP);
2292 if (pincap & AC_PINCAP_OUT) {
2293 err = stac92xx_add_control(spec,
2294 STAC_CTL_WIDGET_IO_SWITCH,
2295 "Line In as Output Switch", nid << 8);
2296 if (err < 0)
2297 return err;
2298 }
2299 }
Matt Porter403d1942005-11-29 15:00:51 +01002300
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002301 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002302 unsigned int def_conf;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002303 nid = cfg->input_pins[AUTO_PIN_MIC];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002304 def_conf = snd_hda_codec_read(codec, nid, 0,
2305 AC_VERB_GET_CONFIG_DEFAULT, 0);
2306
2307 /* some laptops have an internal analog microphone
2308 * which can't be used as a output */
2309 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2310 pincap = snd_hda_param_read(codec, nid,
2311 AC_PAR_PIN_CAP);
2312 if (pincap & AC_PINCAP_OUT) {
2313 err = stac92xx_add_control(spec,
2314 STAC_CTL_WIDGET_IO_SWITCH,
2315 "Mic as Output Switch", (nid << 8) | 1);
2316 if (err < 0)
2317 return err;
2318 }
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002319 }
2320 }
Matt Porter403d1942005-11-29 15:00:51 +01002321
Mattc7d4b2f2005-06-27 14:59:41 +02002322 return 0;
2323}
2324
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002325static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2326{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002327 if (is_in_dac_nids(spec, nid))
2328 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002329 if (spec->multiout.hp_nid == nid)
2330 return 1;
2331 return 0;
2332}
2333
2334static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2335{
2336 if (!spec->multiout.hp_nid)
2337 spec->multiout.hp_nid = nid;
2338 else if (spec->multiout.num_dacs > 4) {
2339 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2340 return 1;
2341 } else {
2342 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2343 spec->multiout.num_dacs++;
2344 }
2345 return 0;
2346}
2347
2348/* add playback controls for Speaker and HP outputs */
2349static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2350 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002351{
2352 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002353 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002354 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002355
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002356 old_num_dacs = spec->multiout.num_dacs;
2357 for (i = 0; i < cfg->hp_outs; i++) {
2358 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2359 if (wid_caps & AC_WCAP_UNSOL_CAP)
2360 spec->hp_detect = 1;
2361 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2362 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2363 if (check_in_dac_nids(spec, nid))
2364 nid = 0;
2365 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002366 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002367 add_spec_dacs(spec, nid);
2368 }
2369 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002370 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002371 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2372 if (check_in_dac_nids(spec, nid))
2373 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002374 if (! nid)
2375 continue;
2376 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002377 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002378 for (i = 0; i < cfg->line_outs; i++) {
2379 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2380 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2381 if (check_in_dac_nids(spec, nid))
2382 nid = 0;
2383 if (! nid)
2384 continue;
2385 add_spec_dacs(spec, nid);
2386 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002387 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2388 static const char *pfxs[] = {
2389 "Speaker", "External Speaker", "Speaker2",
2390 };
2391 err = create_controls(spec, pfxs[i - old_num_dacs],
2392 spec->multiout.dac_nids[i], 3);
2393 if (err < 0)
2394 return err;
2395 }
2396 if (spec->multiout.hp_nid) {
2397 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002398 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002399 pfx = "Master";
2400 else
2401 pfx = "Headphone";
2402 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2403 if (err < 0)
2404 return err;
2405 }
Mattc7d4b2f2005-06-27 14:59:41 +02002406
2407 return 0;
2408}
2409
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002410/* labels for mono mux outputs */
2411static const char *stac92xx_mono_labels[3] = {
2412 "DAC0", "DAC1", "Mixer"
2413};
2414
2415/* create mono mux for mono out on capable codecs */
2416static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2417{
2418 struct sigmatel_spec *spec = codec->spec;
2419 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2420 int i, num_cons;
2421 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2422
2423 num_cons = snd_hda_get_connections(codec,
2424 spec->mono_nid,
2425 con_lst,
2426 HDA_MAX_NUM_INPUTS);
2427 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2428 return -EINVAL;
2429
2430 for (i = 0; i < num_cons; i++) {
2431 mono_mux->items[mono_mux->num_items].label =
2432 stac92xx_mono_labels[i];
2433 mono_mux->items[mono_mux->num_items].index = i;
2434 mono_mux->num_items++;
2435 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002436
2437 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2438 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002439}
2440
Matt Porter8b657272006-10-26 17:12:59 +02002441/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002442static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002443 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2444 "Digital Mic 3", "Digital Mic 4"
2445};
2446
2447/* create playback/capture controls for input pins on dmic capable codecs */
2448static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2449 const struct auto_pin_cfg *cfg)
2450{
2451 struct sigmatel_spec *spec = codec->spec;
2452 struct hda_input_mux *dimux = &spec->private_dimux;
2453 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002454 int err, i, j;
2455 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002456
2457 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2458 dimux->items[dimux->num_items].index = 0;
2459 dimux->num_items++;
2460
2461 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002462 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002463 int index;
2464 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002465 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002466 unsigned int def_conf;
2467
2468 def_conf = snd_hda_codec_read(codec,
2469 spec->dmic_nids[i],
2470 0,
2471 AC_VERB_GET_CONFIG_DEFAULT,
2472 0);
2473 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2474 continue;
2475
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002476 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002477 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002478 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002479 con_lst,
2480 HDA_MAX_NUM_INPUTS);
2481 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002482 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002483 index = j;
2484 goto found;
2485 }
2486 continue;
2487found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002488 wcaps = get_wcaps(codec, nid);
2489
2490 if (wcaps & AC_WCAP_OUT_AMP) {
2491 sprintf(name, "%s Capture Volume",
2492 stac92xx_dmic_labels[dimux->num_items]);
2493
2494 err = stac92xx_add_control(spec,
2495 STAC_CTL_WIDGET_VOL,
2496 name,
2497 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2498 if (err < 0)
2499 return err;
2500 }
2501
Matt Porter8b657272006-10-26 17:12:59 +02002502 dimux->items[dimux->num_items].label =
2503 stac92xx_dmic_labels[dimux->num_items];
2504 dimux->items[dimux->num_items].index = index;
2505 dimux->num_items++;
2506 }
2507
2508 return 0;
2509}
2510
Mattc7d4b2f2005-06-27 14:59:41 +02002511/* create playback/capture controls for input pins */
2512static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2513{
2514 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002515 struct hda_input_mux *imux = &spec->private_imux;
2516 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2517 int i, j, k;
2518
2519 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002520 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002521
Takashi Iwai314634b2006-09-21 11:56:18 +02002522 if (!cfg->input_pins[i])
2523 continue;
2524 index = -1;
2525 for (j = 0; j < spec->num_muxes; j++) {
2526 int num_cons;
2527 num_cons = snd_hda_get_connections(codec,
2528 spec->mux_nids[j],
2529 con_lst,
2530 HDA_MAX_NUM_INPUTS);
2531 for (k = 0; k < num_cons; k++)
2532 if (con_lst[k] == cfg->input_pins[i]) {
2533 index = k;
2534 goto found;
2535 }
Mattc7d4b2f2005-06-27 14:59:41 +02002536 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002537 continue;
2538 found:
2539 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2540 imux->items[imux->num_items].index = index;
2541 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002542 }
2543
Steve Longerbeam7b043892007-05-03 20:50:03 +02002544 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002545 /*
2546 * Set the current input for the muxes.
2547 * The STAC9221 has two input muxes with identical source
2548 * NID lists. Hopefully this won't get confused.
2549 */
2550 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002551 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2552 AC_VERB_SET_CONNECT_SEL,
2553 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002554 }
2555 }
2556
Mattc7d4b2f2005-06-27 14:59:41 +02002557 return 0;
2558}
2559
Mattc7d4b2f2005-06-27 14:59:41 +02002560static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2561{
2562 struct sigmatel_spec *spec = codec->spec;
2563 int i;
2564
2565 for (i = 0; i < spec->autocfg.line_outs; i++) {
2566 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2567 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2568 }
2569}
2570
2571static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2572{
2573 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002574 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002575
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002576 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2577 hda_nid_t pin;
2578 pin = spec->autocfg.hp_pins[i];
2579 if (pin) /* connect to front */
2580 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2581 }
2582 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2583 hda_nid_t pin;
2584 pin = spec->autocfg.speaker_pins[i];
2585 if (pin) /* connect to front */
2586 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2587 }
Mattc7d4b2f2005-06-27 14:59:41 +02002588}
2589
Matt Porter3cc08dc2006-01-23 15:27:49 +01002590static 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 +02002591{
2592 struct sigmatel_spec *spec = codec->spec;
2593 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002594 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002595
Matt Porter8b657272006-10-26 17:12:59 +02002596 if ((err = snd_hda_parse_pin_def_config(codec,
2597 &spec->autocfg,
2598 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002599 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002600 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002601 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002602
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002603 /* If we have no real line-out pin and multiple hp-outs, HPs should
2604 * be set up as multi-channel outputs.
2605 */
2606 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2607 spec->autocfg.hp_outs > 1) {
2608 /* Copy hp_outs to line_outs, backup line_outs in
2609 * speaker_outs so that the following routines can handle
2610 * HP pins as primary outputs.
2611 */
2612 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2613 sizeof(spec->autocfg.line_out_pins));
2614 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2615 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2616 sizeof(spec->autocfg.hp_pins));
2617 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2618 hp_speaker_swap = 1;
2619 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002620 if (spec->autocfg.mono_out_pin) {
2621 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2622 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2623 u32 caps = query_amp_caps(codec,
2624 spec->autocfg.mono_out_pin, dir);
2625 hda_nid_t conn_list[1];
2626
2627 /* get the mixer node and then the mono mux if it exists */
2628 if (snd_hda_get_connections(codec,
2629 spec->autocfg.mono_out_pin, conn_list, 1) &&
2630 snd_hda_get_connections(codec, conn_list[0],
2631 conn_list, 1)) {
2632
2633 int wcaps = get_wcaps(codec, conn_list[0]);
2634 int wid_type = (wcaps & AC_WCAP_TYPE)
2635 >> AC_WCAP_TYPE_SHIFT;
2636 /* LR swap check, some stac925x have a mux that
2637 * changes the DACs output path instead of the
2638 * mono-mux path.
2639 */
2640 if (wid_type == AC_WID_AUD_SEL &&
2641 !(wcaps & AC_WCAP_LR_SWAP))
2642 spec->mono_nid = conn_list[0];
2643 }
2644 /* all mono outs have a least a mute/unmute switch */
2645 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2646 "Mono Playback Switch",
2647 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2648 1, 0, dir));
2649 if (err < 0)
2650 return err;
2651 /* check to see if there is volume support for the amp */
2652 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2653 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2654 "Mono Playback Volume",
2655 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2656 1, 0, dir));
2657 if (err < 0)
2658 return err;
2659 }
2660
2661 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2662 AC_PINCTL_OUT_EN);
2663 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002664
Matt Porter403d1942005-11-29 15:00:51 +01002665 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2666 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002667 if (spec->multiout.num_dacs == 0)
2668 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2669 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002670
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002671 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2672
2673 if (err < 0)
2674 return err;
2675
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002676 if (hp_speaker_swap == 1) {
2677 /* Restore the hp_outs and line_outs */
2678 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2679 sizeof(spec->autocfg.line_out_pins));
2680 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2681 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2682 sizeof(spec->autocfg.speaker_pins));
2683 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2684 memset(spec->autocfg.speaker_pins, 0,
2685 sizeof(spec->autocfg.speaker_pins));
2686 spec->autocfg.speaker_outs = 0;
2687 }
2688
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002689 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2690
2691 if (err < 0)
2692 return err;
2693
2694 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2695
2696 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002697 return err;
2698
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002699 if (spec->mono_nid > 0) {
2700 err = stac92xx_auto_create_mono_output_ctls(codec);
2701 if (err < 0)
2702 return err;
2703 }
2704
Matt Porter8b657272006-10-26 17:12:59 +02002705 if (spec->num_dmics > 0)
2706 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2707 &spec->autocfg)) < 0)
2708 return err;
2709
Mattc7d4b2f2005-06-27 14:59:41 +02002710 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002711 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002712 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002713
Takashi Iwai82bc9552006-03-21 11:24:42 +01002714 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002715 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002716 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002717 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002718
2719 if (spec->kctl_alloc)
2720 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2721
2722 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002723 if (!spec->dinput_mux)
2724 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002725 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002726
2727 return 1;
2728}
2729
Takashi Iwai82bc9552006-03-21 11:24:42 +01002730/* add playback controls for HP output */
2731static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2732 struct auto_pin_cfg *cfg)
2733{
2734 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002735 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002736 unsigned int wid_caps;
2737
2738 if (! pin)
2739 return 0;
2740
2741 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002742 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002743 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002744
2745 return 0;
2746}
2747
Richard Fish160ea0d2006-09-06 13:58:25 +02002748/* add playback controls for LFE output */
2749static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2750 struct auto_pin_cfg *cfg)
2751{
2752 struct sigmatel_spec *spec = codec->spec;
2753 int err;
2754 hda_nid_t lfe_pin = 0x0;
2755 int i;
2756
2757 /*
2758 * search speaker outs and line outs for a mono speaker pin
2759 * with an amp. If one is found, add LFE controls
2760 * for it.
2761 */
2762 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2763 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2764 unsigned long wcaps = get_wcaps(codec, pin);
2765 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2766 if (wcaps == AC_WCAP_OUT_AMP)
2767 /* found a mono speaker with an amp, must be lfe */
2768 lfe_pin = pin;
2769 }
2770
2771 /* if speaker_outs is 0, then speakers may be in line_outs */
2772 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2773 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2774 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2775 unsigned long cfg;
2776 cfg = snd_hda_codec_read(codec, pin, 0,
2777 AC_VERB_GET_CONFIG_DEFAULT,
2778 0x00);
2779 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2780 unsigned long wcaps = get_wcaps(codec, pin);
2781 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2782 if (wcaps == AC_WCAP_OUT_AMP)
2783 /* found a mono speaker with an amp,
2784 must be lfe */
2785 lfe_pin = pin;
2786 }
2787 }
2788 }
2789
2790 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002791 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002792 if (err < 0)
2793 return err;
2794 }
2795
2796 return 0;
2797}
2798
Mattc7d4b2f2005-06-27 14:59:41 +02002799static int stac9200_parse_auto_config(struct hda_codec *codec)
2800{
2801 struct sigmatel_spec *spec = codec->spec;
2802 int err;
2803
Kailang Yangdf694da2005-12-05 19:42:22 +01002804 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002805 return err;
2806
2807 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2808 return err;
2809
Takashi Iwai82bc9552006-03-21 11:24:42 +01002810 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2811 return err;
2812
Richard Fish160ea0d2006-09-06 13:58:25 +02002813 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2814 return err;
2815
Takashi Iwai82bc9552006-03-21 11:24:42 +01002816 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002817 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002818 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002819 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002820
2821 if (spec->kctl_alloc)
2822 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2823
2824 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002825 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002826
2827 return 1;
2828}
2829
Sam Revitch62fe78e2006-05-10 15:09:17 +02002830/*
2831 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2832 * funky external mute control using GPIO pins.
2833 */
2834
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002835static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002836 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002837{
2838 unsigned int gpiostate, gpiomask, gpiodir;
2839
2840 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2841 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002842 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002843
2844 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2845 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002846 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002847
2848 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2849 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002850 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002851
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002852 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002853 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2854
2855 snd_hda_codec_write(codec, codec->afg, 0,
2856 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002857 snd_hda_codec_read(codec, codec->afg, 0,
2858 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002859
2860 msleep(1);
2861
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002862 snd_hda_codec_read(codec, codec->afg, 0,
2863 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002864}
2865
Takashi Iwai314634b2006-09-21 11:56:18 +02002866static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2867 unsigned int event)
2868{
2869 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002870 snd_hda_codec_write_cache(codec, nid, 0,
2871 AC_VERB_SET_UNSOLICITED_ENABLE,
2872 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002873}
2874
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002875static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2876{
2877 int i;
2878 for (i = 0; i < cfg->hp_outs; i++)
2879 if (cfg->hp_pins[i] == nid)
2880 return 1; /* nid is a HP-Out */
2881
2882 return 0; /* nid is not a HP-Out */
2883};
2884
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002885static void stac92xx_power_down(struct hda_codec *codec)
2886{
2887 struct sigmatel_spec *spec = codec->spec;
2888
2889 /* power down inactive DACs */
2890 hda_nid_t *dac;
2891 for (dac = spec->dac_list; *dac; dac++)
2892 if (!is_in_dac_nids(spec, *dac))
2893 snd_hda_codec_write_cache(codec, *dac, 0,
2894 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
2895}
2896
Mattc7d4b2f2005-06-27 14:59:41 +02002897static int stac92xx_init(struct hda_codec *codec)
2898{
2899 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002900 struct auto_pin_cfg *cfg = &spec->autocfg;
2901 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002902
Mattc7d4b2f2005-06-27 14:59:41 +02002903 snd_hda_sequence_write(codec, spec->init);
2904
Takashi Iwai82bc9552006-03-21 11:24:42 +01002905 /* set up pins */
2906 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002907 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002908 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002909 enable_pin_detect(codec, cfg->hp_pins[i],
2910 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002911 /* force to enable the first line-out; the others are set up
2912 * in unsol_event
2913 */
2914 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2915 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002916 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002917 /* fake event to set up pins */
2918 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2919 } else {
2920 stac92xx_auto_init_multi_out(codec);
2921 stac92xx_auto_init_hp_out(codec);
2922 }
2923 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002924 hda_nid_t nid = cfg->input_pins[i];
2925 if (nid) {
2926 unsigned int pinctl = AC_PINCTL_IN_EN;
2927 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2928 pinctl |= stac92xx_get_vref(codec, nid);
2929 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2930 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002931 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002932 for (i = 0; i < spec->num_dmics; i++)
2933 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2934 AC_PINCTL_IN_EN);
2935 for (i = 0; i < spec->num_pwrs; i++) {
2936 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2937 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2938 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2939 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2940 /* outputs are only ports capable of power management
2941 * any attempts on powering down a input port cause the
2942 * referenced VREF to act quirky.
2943 */
2944 if (pinctl & AC_PINCTL_IN_EN)
2945 continue;
2946 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2947 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2948 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002949 if (spec->dac_list)
2950 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002951 if (cfg->dig_out_pin)
2952 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2953 AC_PINCTL_OUT_EN);
2954 if (cfg->dig_in_pin)
2955 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2956 AC_PINCTL_IN_EN);
2957
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002958 stac_gpio_set(codec, spec->gpio_mask,
2959 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002960
Mattc7d4b2f2005-06-27 14:59:41 +02002961 return 0;
2962}
2963
Matt2f2f4252005-04-13 14:45:30 +02002964static void stac92xx_free(struct hda_codec *codec)
2965{
Mattc7d4b2f2005-06-27 14:59:41 +02002966 struct sigmatel_spec *spec = codec->spec;
2967 int i;
2968
2969 if (! spec)
2970 return;
2971
2972 if (spec->kctl_alloc) {
2973 for (i = 0; i < spec->num_kctl_used; i++)
2974 kfree(spec->kctl_alloc[i].name);
2975 kfree(spec->kctl_alloc);
2976 }
2977
Richard Fish11b44bb2006-08-23 18:31:34 +02002978 if (spec->bios_pin_configs)
2979 kfree(spec->bios_pin_configs);
2980
Mattc7d4b2f2005-06-27 14:59:41 +02002981 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002982}
2983
Matt4e550962005-07-04 17:51:39 +02002984static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2985 unsigned int flag)
2986{
2987 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2988 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002989
Takashi Iwaif9acba42007-05-29 18:01:06 +02002990 if (pin_ctl & AC_PINCTL_IN_EN) {
2991 /*
2992 * we need to check the current set-up direction of
2993 * shared input pins since they can be switched via
2994 * "xxx as Output" mixer switch
2995 */
2996 struct sigmatel_spec *spec = codec->spec;
2997 struct auto_pin_cfg *cfg = &spec->autocfg;
2998 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
2999 spec->line_switch) ||
3000 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3001 spec->mic_switch))
3002 return;
3003 }
3004
Steve Longerbeam7b043892007-05-03 20:50:03 +02003005 /* if setting pin direction bits, clear the current
3006 direction bits first */
3007 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3008 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3009
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003010 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003011 AC_VERB_SET_PIN_WIDGET_CONTROL,
3012 pin_ctl | flag);
3013}
3014
3015static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3016 unsigned int flag)
3017{
3018 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3019 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003020 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003021 AC_VERB_SET_PIN_WIDGET_CONTROL,
3022 pin_ctl & ~flag);
3023}
3024
Jiang Zhe40c1d302007-11-12 13:05:16 +01003025static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003026{
3027 if (!nid)
3028 return 0;
3029 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003030 & (1 << 31)) {
3031 unsigned int pinctl;
3032 pinctl = snd_hda_codec_read(codec, nid, 0,
3033 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3034 if (pinctl & AC_PINCTL_IN_EN)
3035 return 0; /* mic- or line-input */
3036 else
3037 return 1; /* HP-output */
3038 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003039 return 0;
3040}
3041
3042static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003043{
3044 struct sigmatel_spec *spec = codec->spec;
3045 struct auto_pin_cfg *cfg = &spec->autocfg;
3046 int i, presence;
3047
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003048 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003049 if (spec->gpio_mute)
3050 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3051 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3052
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003053 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003054 if (presence)
3055 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003056 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003057 }
Matt4e550962005-07-04 17:51:39 +02003058
3059 if (presence) {
3060 /* disable lineouts, enable hp */
3061 for (i = 0; i < cfg->line_outs; i++)
3062 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3063 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003064 for (i = 0; i < cfg->speaker_outs; i++)
3065 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3066 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003067 } else {
3068 /* enable lineouts, disable hp */
3069 for (i = 0; i < cfg->line_outs; i++)
3070 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3071 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003072 for (i = 0; i < cfg->speaker_outs; i++)
3073 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3074 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003075 }
3076}
3077
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003078static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3079{
3080 struct sigmatel_spec *spec = codec->spec;
3081 hda_nid_t nid = spec->pwr_nids[idx];
3082 int presence, val;
3083 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3084 & 0x000000ff;
3085 presence = get_hp_pin_presence(codec, nid);
3086 idx = 1 << idx;
3087
3088 if (presence)
3089 val &= ~idx;
3090 else
3091 val |= idx;
3092
3093 /* power down unused output ports */
3094 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3095};
3096
Takashi Iwai314634b2006-09-21 11:56:18 +02003097static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3098{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003099 struct sigmatel_spec *spec = codec->spec;
3100 int idx = res >> 26 & 0x0f;
3101
3102 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003103 case STAC_HP_EVENT:
3104 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003105 /* fallthru */
3106 case STAC_PWR_EVENT:
3107 if (spec->num_pwrs > 0)
3108 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003109 }
3110}
3111
Takashi Iwaicb53c622007-08-10 17:21:45 +02003112#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003113static int stac92xx_resume(struct hda_codec *codec)
3114{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003115 struct sigmatel_spec *spec = codec->spec;
3116
Richard Fish11b44bb2006-08-23 18:31:34 +02003117 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003118 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003119 stac_gpio_set(codec, spec->gpio_mask,
3120 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003121 snd_hda_codec_resume_amp(codec);
3122 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003123 /* power down inactive DACs */
3124 if (spec->dac_list)
3125 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003126 /* invoke unsolicited event to reset the HP state */
3127 if (spec->hp_detect)
3128 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003129 return 0;
3130}
3131#endif
3132
Matt2f2f4252005-04-13 14:45:30 +02003133static struct hda_codec_ops stac92xx_patch_ops = {
3134 .build_controls = stac92xx_build_controls,
3135 .build_pcms = stac92xx_build_pcms,
3136 .init = stac92xx_init,
3137 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003138 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003139#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003140 .resume = stac92xx_resume,
3141#endif
Matt2f2f4252005-04-13 14:45:30 +02003142};
3143
3144static int patch_stac9200(struct hda_codec *codec)
3145{
3146 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003147 int err;
Matt2f2f4252005-04-13 14:45:30 +02003148
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003149 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003150 if (spec == NULL)
3151 return -ENOMEM;
3152
3153 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003154 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003155 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003156 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3157 stac9200_models,
3158 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003159 if (spec->board_config < 0) {
3160 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3161 err = stac92xx_save_bios_config_regs(codec);
3162 if (err < 0) {
3163 stac92xx_free(codec);
3164 return err;
3165 }
3166 spec->pin_configs = spec->bios_pin_configs;
3167 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003168 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3169 stac92xx_set_config_regs(codec);
3170 }
Matt2f2f4252005-04-13 14:45:30 +02003171
3172 spec->multiout.max_channels = 2;
3173 spec->multiout.num_dacs = 1;
3174 spec->multiout.dac_nids = stac9200_dac_nids;
3175 spec->adc_nids = stac9200_adc_nids;
3176 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003177 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003178 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003179 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003180 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003181
Tobin Davisbf277782008-02-03 20:31:47 +01003182 if (spec->board_config == STAC_9200_GATEWAY ||
3183 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003184 spec->init = stac9200_eapd_init;
3185 else
3186 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003187 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003188
3189 err = stac9200_parse_auto_config(codec);
3190 if (err < 0) {
3191 stac92xx_free(codec);
3192 return err;
3193 }
Matt2f2f4252005-04-13 14:45:30 +02003194
3195 codec->patch_ops = stac92xx_patch_ops;
3196
3197 return 0;
3198}
3199
Tobin Davis8e21c342007-01-08 11:04:17 +01003200static int patch_stac925x(struct hda_codec *codec)
3201{
3202 struct sigmatel_spec *spec;
3203 int err;
3204
3205 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3206 if (spec == NULL)
3207 return -ENOMEM;
3208
3209 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003210 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003211 spec->pin_nids = stac925x_pin_nids;
3212 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3213 stac925x_models,
3214 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003215 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003216 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003217 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3218 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003219 err = stac92xx_save_bios_config_regs(codec);
3220 if (err < 0) {
3221 stac92xx_free(codec);
3222 return err;
3223 }
3224 spec->pin_configs = spec->bios_pin_configs;
3225 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3226 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3227 stac92xx_set_config_regs(codec);
3228 }
3229
3230 spec->multiout.max_channels = 2;
3231 spec->multiout.num_dacs = 1;
3232 spec->multiout.dac_nids = stac925x_dac_nids;
3233 spec->adc_nids = stac925x_adc_nids;
3234 spec->mux_nids = stac925x_mux_nids;
3235 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003236 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003237 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003238 switch (codec->vendor_id) {
3239 case 0x83847632: /* STAC9202 */
3240 case 0x83847633: /* STAC9202D */
3241 case 0x83847636: /* STAC9251 */
3242 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003243 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003244 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003245 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3246 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003247 break;
3248 default:
3249 spec->num_dmics = 0;
3250 break;
3251 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003252
3253 spec->init = stac925x_core_init;
3254 spec->mixer = stac925x_mixer;
3255
3256 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003257 if (!err) {
3258 if (spec->board_config < 0) {
3259 printk(KERN_WARNING "hda_codec: No auto-config is "
3260 "available, default to model=ref\n");
3261 spec->board_config = STAC_925x_REF;
3262 goto again;
3263 }
3264 err = -EINVAL;
3265 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003266 if (err < 0) {
3267 stac92xx_free(codec);
3268 return err;
3269 }
3270
3271 codec->patch_ops = stac92xx_patch_ops;
3272
3273 return 0;
3274}
3275
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003276static struct hda_input_mux stac92hd73xx_dmux = {
3277 .num_items = 4,
3278 .items = {
3279 { "Analog Inputs", 0x0b },
3280 { "CD", 0x08 },
3281 { "Digital Mic 1", 0x09 },
3282 { "Digital Mic 2", 0x0a },
3283 }
3284};
3285
3286static int patch_stac92hd73xx(struct hda_codec *codec)
3287{
3288 struct sigmatel_spec *spec;
3289 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3290 int err = 0;
3291
3292 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3293 if (spec == NULL)
3294 return -ENOMEM;
3295
3296 codec->spec = spec;
3297 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3298 spec->pin_nids = stac92hd73xx_pin_nids;
3299 spec->board_config = snd_hda_check_board_config(codec,
3300 STAC_92HD73XX_MODELS,
3301 stac92hd73xx_models,
3302 stac92hd73xx_cfg_tbl);
3303again:
3304 if (spec->board_config < 0) {
3305 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3306 " STAC92HD73XX, using BIOS defaults\n");
3307 err = stac92xx_save_bios_config_regs(codec);
3308 if (err < 0) {
3309 stac92xx_free(codec);
3310 return err;
3311 }
3312 spec->pin_configs = spec->bios_pin_configs;
3313 } else {
3314 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3315 stac92xx_set_config_regs(codec);
3316 }
3317
3318 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3319 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3320
3321 if (spec->multiout.num_dacs < 0) {
3322 printk(KERN_WARNING "hda_codec: Could not determine "
3323 "number of channels defaulting to DAC count\n");
3324 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3325 }
3326
3327 switch (spec->multiout.num_dacs) {
3328 case 0x3: /* 6 Channel */
3329 spec->mixer = stac92hd73xx_6ch_mixer;
3330 spec->init = stac92hd73xx_6ch_core_init;
3331 break;
3332 case 0x4: /* 8 Channel */
3333 spec->multiout.hp_nid = 0x18;
3334 spec->mixer = stac92hd73xx_8ch_mixer;
3335 spec->init = stac92hd73xx_8ch_core_init;
3336 break;
3337 case 0x5: /* 10 Channel */
3338 spec->multiout.hp_nid = 0x19;
3339 spec->mixer = stac92hd73xx_10ch_mixer;
3340 spec->init = stac92hd73xx_10ch_core_init;
3341 };
3342
3343 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3344 spec->aloopback_mask = 0x01;
3345 spec->aloopback_shift = 8;
3346
3347 spec->mux_nids = stac92hd73xx_mux_nids;
3348 spec->adc_nids = stac92hd73xx_adc_nids;
3349 spec->dmic_nids = stac92hd73xx_dmic_nids;
3350 spec->dmux_nids = stac92hd73xx_dmux_nids;
3351
3352 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3353 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3354 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003355 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003356 spec->dinput_mux = &stac92hd73xx_dmux;
3357 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003358 spec->gpio_mask = spec->gpio_dir = 0x1;
3359 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003360
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003361 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3362 spec->pwr_nids = stac92hd73xx_pwr_nids;
3363
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003364 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3365
3366 if (!err) {
3367 if (spec->board_config < 0) {
3368 printk(KERN_WARNING "hda_codec: No auto-config is "
3369 "available, default to model=ref\n");
3370 spec->board_config = STAC_92HD73XX_REF;
3371 goto again;
3372 }
3373 err = -EINVAL;
3374 }
3375
3376 if (err < 0) {
3377 stac92xx_free(codec);
3378 return err;
3379 }
3380
3381 codec->patch_ops = stac92xx_patch_ops;
3382
3383 return 0;
3384}
3385
Matthew Ranostaye035b842007-11-06 11:53:55 +01003386static int patch_stac92hd71bxx(struct hda_codec *codec)
3387{
3388 struct sigmatel_spec *spec;
3389 int err = 0;
3390
3391 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3392 if (spec == NULL)
3393 return -ENOMEM;
3394
3395 codec->spec = spec;
3396 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3397 spec->pin_nids = stac92hd71bxx_pin_nids;
3398 spec->board_config = snd_hda_check_board_config(codec,
3399 STAC_92HD71BXX_MODELS,
3400 stac92hd71bxx_models,
3401 stac92hd71bxx_cfg_tbl);
3402again:
3403 if (spec->board_config < 0) {
3404 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3405 " STAC92HD71BXX, using BIOS defaults\n");
3406 err = stac92xx_save_bios_config_regs(codec);
3407 if (err < 0) {
3408 stac92xx_free(codec);
3409 return err;
3410 }
3411 spec->pin_configs = spec->bios_pin_configs;
3412 } else {
3413 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3414 stac92xx_set_config_regs(codec);
3415 }
3416
Matthew Ranostay541eee82007-12-14 12:08:04 +01003417 switch (codec->vendor_id) {
3418 case 0x111d76b6: /* 4 Port without Analog Mixer */
3419 case 0x111d76b7:
3420 case 0x111d76b4: /* 6 Port without Analog Mixer */
3421 case 0x111d76b5:
3422 spec->mixer = stac92hd71bxx_mixer;
3423 spec->init = stac92hd71bxx_core_init;
3424 break;
3425 default:
3426 spec->mixer = stac92hd71bxx_analog_mixer;
3427 spec->init = stac92hd71bxx_analog_core_init;
3428 }
3429
3430 spec->aloopback_mask = 0x20;
3431 spec->aloopback_shift = 0;
3432
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003433 /* GPIO0 High = EAPD */
3434 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003435
Matthew Ranostaye035b842007-11-06 11:53:55 +01003436 spec->mux_nids = stac92hd71bxx_mux_nids;
3437 spec->adc_nids = stac92hd71bxx_adc_nids;
3438 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003439 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003440
3441 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3442 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3443 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003444 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003445
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003446 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3447 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3448
Matthew Ranostaye035b842007-11-06 11:53:55 +01003449 spec->multiout.num_dacs = 2;
3450 spec->multiout.hp_nid = 0x11;
3451 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3452
3453 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3454 if (!err) {
3455 if (spec->board_config < 0) {
3456 printk(KERN_WARNING "hda_codec: No auto-config is "
3457 "available, default to model=ref\n");
3458 spec->board_config = STAC_92HD71BXX_REF;
3459 goto again;
3460 }
3461 err = -EINVAL;
3462 }
3463
3464 if (err < 0) {
3465 stac92xx_free(codec);
3466 return err;
3467 }
3468
3469 codec->patch_ops = stac92xx_patch_ops;
3470
3471 return 0;
3472};
3473
Matt2f2f4252005-04-13 14:45:30 +02003474static int patch_stac922x(struct hda_codec *codec)
3475{
3476 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003477 int err;
Matt2f2f4252005-04-13 14:45:30 +02003478
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003479 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003480 if (spec == NULL)
3481 return -ENOMEM;
3482
3483 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003484 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003485 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003486 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3487 stac922x_models,
3488 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003489 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003490 spec->gpio_mask = spec->gpio_dir = 0x03;
3491 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003492 /* Intel Macs have all same PCI SSID, so we need to check
3493 * codec SSID to distinguish the exact models
3494 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003495 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003496 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003497
3498 case 0x106b0800:
3499 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003500 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003501 case 0x106b0600:
3502 case 0x106b0700:
3503 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003504 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003505 case 0x106b0e00:
3506 case 0x106b0f00:
3507 case 0x106b1600:
3508 case 0x106b1700:
3509 case 0x106b0200:
3510 case 0x106b1e00:
3511 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003512 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003513 case 0x106b1a00:
3514 case 0x00000100:
3515 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003516 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003517 case 0x106b0a00:
3518 case 0x106b2200:
3519 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003520 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003521 }
3522 }
3523
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003524 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003525 if (spec->board_config < 0) {
3526 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3527 "using BIOS defaults\n");
3528 err = stac92xx_save_bios_config_regs(codec);
3529 if (err < 0) {
3530 stac92xx_free(codec);
3531 return err;
3532 }
3533 spec->pin_configs = spec->bios_pin_configs;
3534 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003535 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3536 stac92xx_set_config_regs(codec);
3537 }
Matt2f2f4252005-04-13 14:45:30 +02003538
Matt2f2f4252005-04-13 14:45:30 +02003539 spec->adc_nids = stac922x_adc_nids;
3540 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003541 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003542 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003543 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003544 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003545
3546 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003547 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003548
3549 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003550
Matt Porter3cc08dc2006-01-23 15:27:49 +01003551 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003552 if (!err) {
3553 if (spec->board_config < 0) {
3554 printk(KERN_WARNING "hda_codec: No auto-config is "
3555 "available, default to model=ref\n");
3556 spec->board_config = STAC_D945_REF;
3557 goto again;
3558 }
3559 err = -EINVAL;
3560 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003561 if (err < 0) {
3562 stac92xx_free(codec);
3563 return err;
3564 }
3565
3566 codec->patch_ops = stac92xx_patch_ops;
3567
Takashi Iwai807a46362007-05-29 19:01:37 +02003568 /* Fix Mux capture level; max to 2 */
3569 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3570 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3571 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3572 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3573 (0 << AC_AMPCAP_MUTE_SHIFT));
3574
Matt Porter3cc08dc2006-01-23 15:27:49 +01003575 return 0;
3576}
3577
3578static int patch_stac927x(struct hda_codec *codec)
3579{
3580 struct sigmatel_spec *spec;
3581 int err;
3582
3583 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3584 if (spec == NULL)
3585 return -ENOMEM;
3586
3587 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003588 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003589 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003590 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3591 stac927x_models,
3592 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003593 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003594 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3595 if (spec->board_config < 0)
3596 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3597 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003598 err = stac92xx_save_bios_config_regs(codec);
3599 if (err < 0) {
3600 stac92xx_free(codec);
3601 return err;
3602 }
3603 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003604 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003605 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3606 stac92xx_set_config_regs(codec);
3607 }
3608
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003609 spec->adc_nids = stac927x_adc_nids;
3610 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3611 spec->mux_nids = stac927x_mux_nids;
3612 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003613 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003614 spec->multiout.dac_nids = spec->dac_nids;
3615
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003616 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003617 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003618 case STAC_D965_5ST:
3619 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003620 spec->gpio_mask = spec->gpio_dir = 0x01;
3621 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003622 spec->num_dmics = 0;
3623
Tobin Davis93ed1502006-09-01 21:03:12 +02003624 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003625 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003626 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003627 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003628 /* correct the front output jack as a hp out */
3629 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003630 /* correct the front input jack as a mic */
3631 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3632 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003633 case STAC_DELL_3ST:
3634 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003635 spec->gpio_mask = spec->gpio_dir = 0x04;
3636 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003637 spec->dmic_nids = stac927x_dmic_nids;
3638 spec->num_dmics = STAC927X_NUM_DMICS;
3639
Tobin Davis93ed1502006-09-01 21:03:12 +02003640 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003641 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003642 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003643 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003644 break;
3645 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003646 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003647 spec->gpio_mask = spec->gpio_dir = 0x1;
3648 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003649 spec->num_dmics = 0;
3650
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003651 spec->init = stac927x_core_init;
3652 spec->mixer = stac927x_mixer;
3653 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003654
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003655 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003656 spec->aloopback_mask = 0x40;
3657 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003658
Matt Porter3cc08dc2006-01-23 15:27:49 +01003659 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003660 if (!err) {
3661 if (spec->board_config < 0) {
3662 printk(KERN_WARNING "hda_codec: No auto-config is "
3663 "available, default to model=ref\n");
3664 spec->board_config = STAC_D965_REF;
3665 goto again;
3666 }
3667 err = -EINVAL;
3668 }
Mattc7d4b2f2005-06-27 14:59:41 +02003669 if (err < 0) {
3670 stac92xx_free(codec);
3671 return err;
3672 }
Matt2f2f4252005-04-13 14:45:30 +02003673
3674 codec->patch_ops = stac92xx_patch_ops;
3675
Takashi Iwai52987652008-01-16 16:09:47 +01003676 /*
3677 * !!FIXME!!
3678 * The STAC927x seem to require fairly long delays for certain
3679 * command sequences. With too short delays (even if the answer
3680 * is set to RIRB properly), it results in the silence output
3681 * on some hardwares like Dell.
3682 *
3683 * The below flag enables the longer delay (see get_response
3684 * in hda_intel.c).
3685 */
3686 codec->bus->needs_damn_long_delay = 1;
3687
Matt2f2f4252005-04-13 14:45:30 +02003688 return 0;
3689}
3690
Matt Porterf3302a52006-07-31 12:49:34 +02003691static int patch_stac9205(struct hda_codec *codec)
3692{
3693 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003694 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003695
3696 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3697 if (spec == NULL)
3698 return -ENOMEM;
3699
3700 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003701 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003702 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003703 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3704 stac9205_models,
3705 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003706 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003707 if (spec->board_config < 0) {
3708 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3709 err = stac92xx_save_bios_config_regs(codec);
3710 if (err < 0) {
3711 stac92xx_free(codec);
3712 return err;
3713 }
3714 spec->pin_configs = spec->bios_pin_configs;
3715 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003716 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3717 stac92xx_set_config_regs(codec);
3718 }
3719
3720 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003721 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003722 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003723 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003724 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003725 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003726 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003727 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003728 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003729
3730 spec->init = stac9205_core_init;
3731 spec->mixer = stac9205_mixer;
3732
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003733 spec->aloopback_mask = 0x40;
3734 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003735 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003736
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003737 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003738 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003739 /* Enable SPDIF in/out */
3740 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3741 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003742
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003743 /* Enable unsol response for GPIO4/Dock HP connection */
3744 snd_hda_codec_write(codec, codec->afg, 0,
3745 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3746 snd_hda_codec_write_cache(codec, codec->afg, 0,
3747 AC_VERB_SET_UNSOLICITED_ENABLE,
3748 (AC_USRSP_EN | STAC_HP_EVENT));
3749
3750 spec->gpio_dir = 0x0b;
3751 spec->gpio_mask = 0x1b;
3752 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003753 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003754 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003755 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003756 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003757 break;
3758 default:
3759 /* GPIO0 High = EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003760 spec->gpio_mask = spec->gpio_dir = 0x1;
3761 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003762 break;
3763 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003764
Matt Porterf3302a52006-07-31 12:49:34 +02003765 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003766 if (!err) {
3767 if (spec->board_config < 0) {
3768 printk(KERN_WARNING "hda_codec: No auto-config is "
3769 "available, default to model=ref\n");
3770 spec->board_config = STAC_9205_REF;
3771 goto again;
3772 }
3773 err = -EINVAL;
3774 }
Matt Porterf3302a52006-07-31 12:49:34 +02003775 if (err < 0) {
3776 stac92xx_free(codec);
3777 return err;
3778 }
3779
3780 codec->patch_ops = stac92xx_patch_ops;
3781
3782 return 0;
3783}
3784
Matt2f2f4252005-04-13 14:45:30 +02003785/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003786 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003787 */
3788
Guillaume Munch99ccc562006-08-16 19:35:12 +02003789/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003790static hda_nid_t vaio_dacs[] = { 0x2 };
3791#define VAIO_HP_DAC 0x5
3792static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3793static hda_nid_t vaio_mux_nids[] = { 0x15 };
3794
3795static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003796 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003797 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003798 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003799 { "Mic Jack", 0x1 },
3800 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003801 { "PCM", 0x3 },
3802 }
3803};
3804
3805static struct hda_verb vaio_init[] = {
3806 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003807 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003808 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3809 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3810 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3811 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003812 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003813 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3814 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3815 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3816 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3817 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3818 {}
3819};
3820
Guillaume Munch6d859062006-08-22 17:15:47 +02003821static struct hda_verb vaio_ar_init[] = {
3822 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3823 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3824 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3825 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3826/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3827 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003828 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003829 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3830 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3831/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3832 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3833 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3834 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3835 {}
3836};
3837
Takashi Iwaidb064e52006-03-16 16:04:58 +01003838/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003839static struct hda_bind_ctls vaio_bind_master_vol = {
3840 .ops = &snd_hda_bind_vol,
3841 .values = {
3842 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3843 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3844 0
3845 },
3846};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003847
3848/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003849static struct hda_bind_ctls vaio_bind_master_sw = {
3850 .ops = &snd_hda_bind_sw,
3851 .values = {
3852 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3853 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3854 0,
3855 },
3856};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003857
3858static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003859 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3860 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003861 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3862 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3863 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3864 {
3865 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3866 .name = "Capture Source",
3867 .count = 1,
3868 .info = stac92xx_mux_enum_info,
3869 .get = stac92xx_mux_enum_get,
3870 .put = stac92xx_mux_enum_put,
3871 },
3872 {}
3873};
3874
Guillaume Munch6d859062006-08-22 17:15:47 +02003875static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003876 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3877 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003878 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3879 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3880 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3881 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3882 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3883 {
3884 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3885 .name = "Capture Source",
3886 .count = 1,
3887 .info = stac92xx_mux_enum_info,
3888 .get = stac92xx_mux_enum_get,
3889 .put = stac92xx_mux_enum_put,
3890 },
3891 {}
3892};
3893
3894static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003895 .build_controls = stac92xx_build_controls,
3896 .build_pcms = stac92xx_build_pcms,
3897 .init = stac92xx_init,
3898 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003899#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003900 .resume = stac92xx_resume,
3901#endif
3902};
3903
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003904static int stac9872_vaio_init(struct hda_codec *codec)
3905{
3906 int err;
3907
3908 err = stac92xx_init(codec);
3909 if (err < 0)
3910 return err;
3911 if (codec->patch_ops.unsol_event)
3912 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3913 return 0;
3914}
3915
3916static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3917{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003918 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003919 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3920 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3921 } else {
3922 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3923 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3924 }
3925}
3926
3927static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3928{
3929 switch (res >> 26) {
3930 case STAC_HP_EVENT:
3931 stac9872_vaio_hp_detect(codec, res);
3932 break;
3933 }
3934}
3935
3936static struct hda_codec_ops stac9872_vaio_patch_ops = {
3937 .build_controls = stac92xx_build_controls,
3938 .build_pcms = stac92xx_build_pcms,
3939 .init = stac9872_vaio_init,
3940 .free = stac92xx_free,
3941 .unsol_event = stac9872_vaio_unsol_event,
3942#ifdef CONFIG_PM
3943 .resume = stac92xx_resume,
3944#endif
3945};
3946
Guillaume Munch6d859062006-08-22 17:15:47 +02003947enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3948 CXD9872RD_VAIO,
3949 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3950 STAC9872AK_VAIO,
3951 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3952 STAC9872K_VAIO,
3953 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003954 CXD9872AKD_VAIO,
3955 STAC_9872_MODELS,
3956};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003957
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003958static const char *stac9872_models[STAC_9872_MODELS] = {
3959 [CXD9872RD_VAIO] = "vaio",
3960 [CXD9872AKD_VAIO] = "vaio-ar",
3961};
3962
3963static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3964 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3965 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3966 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003967 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003968 {}
3969};
3970
Guillaume Munch6d859062006-08-22 17:15:47 +02003971static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003972{
3973 struct sigmatel_spec *spec;
3974 int board_config;
3975
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003976 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3977 stac9872_models,
3978 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003979 if (board_config < 0)
3980 /* unknown config, let generic-parser do its job... */
3981 return snd_hda_parse_generic_codec(codec);
3982
3983 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3984 if (spec == NULL)
3985 return -ENOMEM;
3986
3987 codec->spec = spec;
3988 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003989 case CXD9872RD_VAIO:
3990 case STAC9872AK_VAIO:
3991 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003992 spec->mixer = vaio_mixer;
3993 spec->init = vaio_init;
3994 spec->multiout.max_channels = 2;
3995 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
3996 spec->multiout.dac_nids = vaio_dacs;
3997 spec->multiout.hp_nid = VAIO_HP_DAC;
3998 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
3999 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004000 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004001 spec->input_mux = &vaio_mux;
4002 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004003 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004004 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004005
4006 case CXD9872AKD_VAIO:
4007 spec->mixer = vaio_ar_mixer;
4008 spec->init = vaio_ar_init;
4009 spec->multiout.max_channels = 2;
4010 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4011 spec->multiout.dac_nids = vaio_dacs;
4012 spec->multiout.hp_nid = VAIO_HP_DAC;
4013 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004014 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004015 spec->adc_nids = vaio_adcs;
4016 spec->input_mux = &vaio_mux;
4017 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004018 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004019 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004020 }
4021
Takashi Iwaidb064e52006-03-16 16:04:58 +01004022 return 0;
4023}
4024
4025
4026/*
Matt2f2f4252005-04-13 14:45:30 +02004027 * patch entries
4028 */
4029struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4030 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4031 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4032 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4033 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4034 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4035 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4036 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004037 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4038 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4039 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4040 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4041 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4042 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004043 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4044 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4045 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4046 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4047 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4048 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4049 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4050 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4051 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4052 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004053 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4054 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4055 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4056 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4057 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4058 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004059 /* The following does not take into account .id=0x83847661 when subsys =
4060 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4061 * currently not fully supported.
4062 */
4063 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4064 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4065 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004066 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4067 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4068 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4069 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4070 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4071 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4072 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4073 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004074 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4075 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004076 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004077 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4078 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4079 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4080 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4081 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4082 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4083 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4084 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4085 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004086 {} /* terminator */
4087};