blob: 7901e76f269066753b5eec6b6cd7012b8a22c326 [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;
Takashi Iwai9a081602008-02-12 18:37:26 +0100919 err = snd_hda_create_spdif_share_sw(codec,
920 &spec->multiout);
921 if (err < 0)
922 return err;
923 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200924 }
925 if (spec->dig_in_nid) {
926 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
927 if (err < 0)
928 return err;
929 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100930
931 /* if we have no master control, let's create it */
932 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
933 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
934 HDA_OUTPUT, spec->vmaster_tlv);
935 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
936 spec->vmaster_tlv, slave_vols);
937 if (err < 0)
938 return err;
939 }
940 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
941 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
942 NULL, slave_sws);
943 if (err < 0)
944 return err;
945 }
946
Mattdabbed62005-06-14 10:19:34 +0200947 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200948}
949
Matt Porter403d1942005-11-29 15:00:51 +0100950static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200951 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200952 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
953};
954
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200955/*
956 STAC 9200 pin configs for
957 102801A8
958 102801DE
959 102801E8
960*/
961static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200962 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
963 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200964};
965
966/*
967 STAC 9200 pin configs for
968 102801C0
969 102801C1
970*/
971static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200972 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
973 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200974};
975
976/*
977 STAC 9200 pin configs for
978 102801C4 (Dell Dimension E310)
979 102801C5
980 102801C7
981 102801D9
982 102801DA
983 102801E3
984*/
985static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200986 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
987 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200988};
989
990
991/*
992 STAC 9200-32 pin configs for
993 102801B5 (Dell Inspiron 630m)
994 102801D8 (Dell Inspiron 640m)
995*/
996static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +0200997 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
998 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200999};
1000
1001/*
1002 STAC 9200-32 pin configs for
1003 102801C2 (Dell Latitude D620)
1004 102801C8
1005 102801CC (Dell Latitude D820)
1006 102801D4
1007 102801D6
1008*/
1009static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001010 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1011 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001012};
1013
1014/*
1015 STAC 9200-32 pin configs for
1016 102801CE (Dell XPS M1710)
1017 102801CF (Dell Precision M90)
1018*/
1019static unsigned int dell9200_m23_pin_configs[8] = {
1020 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1021 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1022};
1023
1024/*
1025 STAC 9200-32 pin configs for
1026 102801C9
1027 102801CA
1028 102801CB (Dell Latitude 120L)
1029 102801D3
1030*/
1031static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001032 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1033 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001034};
1035
1036/*
1037 STAC 9200-32 pin configs for
1038 102801BD (Dell Inspiron E1505n)
1039 102801EE
1040 102801EF
1041*/
1042static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001043 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1044 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001045};
1046
1047/*
1048 STAC 9200-32 pin configs for
1049 102801F5 (Dell Inspiron 1501)
1050 102801F6
1051*/
1052static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001053 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1054 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001055};
1056
1057/*
1058 STAC 9200-32
1059 102801CD (Dell Inspiron E1705/9400)
1060*/
1061static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001062 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1063 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001064};
1065
Tobin Davisbf277782008-02-03 20:31:47 +01001066static unsigned int oqo9200_pin_configs[8] = {
1067 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1068 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1069};
1070
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001071
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001072static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1073 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001074 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001075 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1076 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1077 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1078 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1079 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1080 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1081 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1082 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1083 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1084 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001085};
1086
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001087static const char *stac9200_models[STAC_9200_MODELS] = {
1088 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001089 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001090 [STAC_9200_DELL_D21] = "dell-d21",
1091 [STAC_9200_DELL_D22] = "dell-d22",
1092 [STAC_9200_DELL_D23] = "dell-d23",
1093 [STAC_9200_DELL_M21] = "dell-m21",
1094 [STAC_9200_DELL_M22] = "dell-m22",
1095 [STAC_9200_DELL_M23] = "dell-m23",
1096 [STAC_9200_DELL_M24] = "dell-m24",
1097 [STAC_9200_DELL_M25] = "dell-m25",
1098 [STAC_9200_DELL_M26] = "dell-m26",
1099 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001100 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001101};
1102
1103static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1104 /* SigmaTel reference board */
1105 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1106 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001107 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001108 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1109 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001110 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001111 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1112 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1113 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1114 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1115 "unknown Dell", STAC_9200_DELL_D22),
1116 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1117 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001118 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001119 "Dell Latitude D620", STAC_9200_DELL_M22),
1120 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1121 "unknown Dell", STAC_9200_DELL_D23),
1122 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1123 "unknown Dell", STAC_9200_DELL_D23),
1124 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1125 "unknown Dell", STAC_9200_DELL_M22),
1126 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1127 "unknown Dell", STAC_9200_DELL_M24),
1128 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1129 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001130 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001131 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001132 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001133 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001134 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001135 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001136 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001137 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001138 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001139 "Dell Precision M90", STAC_9200_DELL_M23),
1140 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1141 "unknown Dell", STAC_9200_DELL_M22),
1142 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1143 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001144 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001145 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001146 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001147 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1148 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1149 "unknown Dell", STAC_9200_DELL_D23),
1150 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1151 "unknown Dell", STAC_9200_DELL_D23),
1152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1153 "unknown Dell", STAC_9200_DELL_D21),
1154 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1155 "unknown Dell", STAC_9200_DELL_D23),
1156 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1157 "unknown Dell", STAC_9200_DELL_D21),
1158 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1159 "unknown Dell", STAC_9200_DELL_M25),
1160 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1161 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001162 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001163 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1164 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1165 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001166 /* Panasonic */
1167 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001168 /* Gateway machines needs EAPD to be set on resume */
1169 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1170 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1171 STAC_9200_GATEWAY),
1172 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1173 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001174 /* OQO Mobile */
1175 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001176 {} /* terminator */
1177};
1178
Tobin Davis8e21c342007-01-08 11:04:17 +01001179static unsigned int ref925x_pin_configs[8] = {
1180 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001181 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001182};
1183
1184static unsigned int stac925x_MA6_pin_configs[8] = {
1185 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1186 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1187};
1188
Tobin Davis2c11f952007-05-17 09:36:34 +02001189static unsigned int stac925x_PA6_pin_configs[8] = {
1190 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1191 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1192};
1193
Tobin Davis8e21c342007-01-08 11:04:17 +01001194static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001195 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1196 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001197};
1198
1199static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1200 [STAC_REF] = ref925x_pin_configs,
1201 [STAC_M2_2] = stac925xM2_2_pin_configs,
1202 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001203 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001204};
1205
1206static const char *stac925x_models[STAC_925x_MODELS] = {
1207 [STAC_REF] = "ref",
1208 [STAC_M2_2] = "m2-2",
1209 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001210 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001211};
1212
1213static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1214 /* SigmaTel reference board */
1215 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001216 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001217 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1218 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1219 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001220 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001221 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1222 {} /* terminator */
1223};
1224
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001225static unsigned int ref92hd73xx_pin_configs[12] = {
1226 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1227 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1228 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
1229};
1230
1231static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
1232 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1233};
1234
1235static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1236 [STAC_92HD73XX_REF] = "ref",
1237};
1238
1239static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1240 /* SigmaTel reference board */
1241 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1242 "DFI LanParty", STAC_92HD73XX_REF),
1243 {} /* terminator */
1244};
1245
Matthew Ranostaye035b842007-11-06 11:53:55 +01001246static unsigned int ref92hd71bxx_pin_configs[10] = {
1247 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001248 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001249 0x90a000f0, 0x01452050,
1250};
1251
1252static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1253 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
1254};
1255
1256static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1257 [STAC_92HD71BXX_REF] = "ref",
1258};
1259
1260static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1261 /* SigmaTel reference board */
1262 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1263 "DFI LanParty", STAC_92HD71BXX_REF),
1264 {} /* terminator */
1265};
1266
Matt Porter403d1942005-11-29 15:00:51 +01001267static unsigned int ref922x_pin_configs[10] = {
1268 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1269 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001270 0x40000100, 0x40000100,
1271};
1272
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001273/*
1274 STAC 922X pin configs for
1275 102801A7
1276 102801AB
1277 102801A9
1278 102801D1
1279 102801D2
1280*/
1281static unsigned int dell_922x_d81_pin_configs[10] = {
1282 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1283 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1284 0x01813122, 0x400001f2,
1285};
1286
1287/*
1288 STAC 922X pin configs for
1289 102801AC
1290 102801D0
1291*/
1292static unsigned int dell_922x_d82_pin_configs[10] = {
1293 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1294 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1295 0x01813122, 0x400001f1,
1296};
1297
1298/*
1299 STAC 922X pin configs for
1300 102801BF
1301*/
1302static unsigned int dell_922x_m81_pin_configs[10] = {
1303 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1304 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1305 0x40C003f1, 0x405003f0,
1306};
1307
1308/*
1309 STAC 9221 A1 pin configs for
1310 102801D7 (Dell XPS M1210)
1311*/
1312static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001313 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1314 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001315 0x508003f3, 0x405003f4,
1316};
1317
Matt Porter403d1942005-11-29 15:00:51 +01001318static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001319 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001320 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1321 0x02a19120, 0x40000100,
1322};
1323
1324static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001325 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1326 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001327 0x02a19320, 0x40000100,
1328};
1329
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001330static unsigned int intel_mac_v1_pin_configs[10] = {
1331 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1332 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001333 0x400000fc, 0x400000fb,
1334};
1335
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001336static unsigned int intel_mac_v2_pin_configs[10] = {
1337 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1338 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001339 0x400000fc, 0x400000fb,
1340};
1341
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001342static unsigned int intel_mac_v3_pin_configs[10] = {
1343 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1344 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1345 0x400000fc, 0x400000fb,
1346};
1347
1348static unsigned int intel_mac_v4_pin_configs[10] = {
1349 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1350 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1351 0x400000fc, 0x400000fb,
1352};
1353
1354static unsigned int intel_mac_v5_pin_configs[10] = {
1355 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1356 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1357 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001358};
1359
Takashi Iwai76c08822007-06-19 12:17:42 +02001360
Takashi Iwai19039bd2006-06-28 15:52:16 +02001361static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001362 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001363 [STAC_D945GTP3] = d945gtp3_pin_configs,
1364 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001365 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1366 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1367 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1368 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1369 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001370 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001371 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1372 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1373 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1374 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1375 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1376 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001377 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1378 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1379 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1380 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001381};
1382
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001383static const char *stac922x_models[STAC_922X_MODELS] = {
1384 [STAC_D945_REF] = "ref",
1385 [STAC_D945GTP5] = "5stack",
1386 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001387 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1388 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1389 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1390 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1391 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001392 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001393 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001394 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001395 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1396 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001397 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001398 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001399 [STAC_922X_DELL_D81] = "dell-d81",
1400 [STAC_922X_DELL_D82] = "dell-d82",
1401 [STAC_922X_DELL_M81] = "dell-m81",
1402 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001403};
1404
1405static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1406 /* SigmaTel reference board */
1407 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1408 "DFI LanParty", STAC_D945_REF),
1409 /* Intel 945G based systems */
1410 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1411 "Intel D945G", STAC_D945GTP3),
1412 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1413 "Intel D945G", STAC_D945GTP3),
1414 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1415 "Intel D945G", STAC_D945GTP3),
1416 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1417 "Intel D945G", STAC_D945GTP3),
1418 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1419 "Intel D945G", STAC_D945GTP3),
1420 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1421 "Intel D945G", STAC_D945GTP3),
1422 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1423 "Intel D945G", STAC_D945GTP3),
1424 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1425 "Intel D945G", STAC_D945GTP3),
1426 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1427 "Intel D945G", STAC_D945GTP3),
1428 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1429 "Intel D945G", STAC_D945GTP3),
1430 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1431 "Intel D945G", STAC_D945GTP3),
1432 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1433 "Intel D945G", STAC_D945GTP3),
1434 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1435 "Intel D945G", STAC_D945GTP3),
1436 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1437 "Intel D945G", STAC_D945GTP3),
1438 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1439 "Intel D945G", STAC_D945GTP3),
1440 /* Intel D945G 5-stack systems */
1441 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1442 "Intel D945G", STAC_D945GTP5),
1443 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1444 "Intel D945G", STAC_D945GTP5),
1445 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1446 "Intel D945G", STAC_D945GTP5),
1447 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1448 "Intel D945G", STAC_D945GTP5),
1449 /* Intel 945P based systems */
1450 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1451 "Intel D945P", STAC_D945GTP3),
1452 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1453 "Intel D945P", STAC_D945GTP3),
1454 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1455 "Intel D945P", STAC_D945GTP3),
1456 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1457 "Intel D945P", STAC_D945GTP3),
1458 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1459 "Intel D945P", STAC_D945GTP3),
1460 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1461 "Intel D945P", STAC_D945GTP5),
1462 /* other systems */
1463 /* Apple Mac Mini (early 2006) */
1464 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001465 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001466 /* Dell systems */
1467 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1468 "unknown Dell", STAC_922X_DELL_D81),
1469 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1470 "unknown Dell", STAC_922X_DELL_D81),
1471 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1472 "unknown Dell", STAC_922X_DELL_D81),
1473 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1474 "unknown Dell", STAC_922X_DELL_D82),
1475 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1476 "unknown Dell", STAC_922X_DELL_M81),
1477 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1478 "unknown Dell", STAC_922X_DELL_D82),
1479 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1480 "unknown Dell", STAC_922X_DELL_D81),
1481 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1482 "unknown Dell", STAC_922X_DELL_D81),
1483 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1484 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001485 {} /* terminator */
1486};
1487
Matt Porter3cc08dc2006-01-23 15:27:49 +01001488static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001489 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1490 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1491 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1492 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001493};
1494
Tobin Davis93ed1502006-09-01 21:03:12 +02001495static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001496 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1497 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1498 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1499 0x40000100, 0x40000100
1500};
1501
Tobin Davis93ed1502006-09-01 21:03:12 +02001502static unsigned int d965_5st_pin_configs[14] = {
1503 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1504 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1505 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1506 0x40000100, 0x40000100
1507};
1508
Tobin Davis4ff076e2007-08-07 11:48:12 +02001509static unsigned int dell_3st_pin_configs[14] = {
1510 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1511 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001512 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001513 0x40c003fc, 0x40000100
1514};
1515
Tobin Davis93ed1502006-09-01 21:03:12 +02001516static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001517 [STAC_D965_REF] = ref927x_pin_configs,
1518 [STAC_D965_3ST] = d965_3st_pin_configs,
1519 [STAC_D965_5ST] = d965_5st_pin_configs,
1520 [STAC_DELL_3ST] = dell_3st_pin_configs,
1521 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001522};
1523
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001524static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001525 [STAC_D965_REF] = "ref",
1526 [STAC_D965_3ST] = "3stack",
1527 [STAC_D965_5ST] = "5stack",
1528 [STAC_DELL_3ST] = "dell-3stack",
1529 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001530};
1531
1532static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1533 /* SigmaTel reference board */
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1535 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001536 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001539 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1554 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001556 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001557 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001558 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001559 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1560 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001561 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001562 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1563 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001564 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1565 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1566 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1567 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1569 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001570 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001571 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1572 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1573 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1575 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1576 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1577 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1578 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1579 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001580 {} /* terminator */
1581};
1582
Matt Porterf3302a52006-07-31 12:49:34 +02001583static unsigned int ref9205_pin_configs[12] = {
1584 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001585 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001586 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001587};
1588
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001589/*
1590 STAC 9205 pin configs for
1591 102801F1
1592 102801F2
1593 102801FC
1594 102801FD
1595 10280204
1596 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001597 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001598*/
1599static unsigned int dell_9205_m42_pin_configs[12] = {
1600 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1601 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1602 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1603};
1604
1605/*
1606 STAC 9205 pin configs for
1607 102801F9
1608 102801FA
1609 102801FE
1610 102801FF (Dell Precision M4300)
1611 10280206
1612 10280200
1613 10280201
1614*/
1615static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001616 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1617 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1618 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1619};
1620
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001621static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001622 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1623 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1624 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1625};
1626
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001627static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001628 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001629 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1630 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1631 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001632};
1633
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001634static const char *stac9205_models[STAC_9205_MODELS] = {
1635 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001636 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001637 [STAC_9205_DELL_M43] = "dell-m43",
1638 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001639};
1640
1641static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1642 /* SigmaTel reference board */
1643 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1644 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1646 "unknown Dell", STAC_9205_DELL_M42),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1648 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001649 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001650 "Dell Precision", STAC_9205_DELL_M43),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1652 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001653 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1654 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001655 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1656 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001657 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1658 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001659 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1660 "unknown Dell", STAC_9205_DELL_M42),
1661 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1662 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001663 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1664 "Dell Precision", STAC_9205_DELL_M43),
1665 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001666 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001667 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1668 "Dell Precision", STAC_9205_DELL_M43),
1669 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1670 "Dell Inspiron", STAC_9205_DELL_M44),
1671 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1672 "Dell Inspiron", STAC_9205_DELL_M44),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1674 "Dell Inspiron", STAC_9205_DELL_M44),
1675 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1676 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001677 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1678 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001679 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1680 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001681 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1682 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001683 {} /* terminator */
1684};
1685
Richard Fish11b44bb2006-08-23 18:31:34 +02001686static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1687{
1688 int i;
1689 struct sigmatel_spec *spec = codec->spec;
1690
1691 if (! spec->bios_pin_configs) {
1692 spec->bios_pin_configs = kcalloc(spec->num_pins,
1693 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1694 if (! spec->bios_pin_configs)
1695 return -ENOMEM;
1696 }
1697
1698 for (i = 0; i < spec->num_pins; i++) {
1699 hda_nid_t nid = spec->pin_nids[i];
1700 unsigned int pin_cfg;
1701
1702 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1703 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1704 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1705 nid, pin_cfg);
1706 spec->bios_pin_configs[i] = pin_cfg;
1707 }
1708
1709 return 0;
1710}
1711
Matthew Ranostay87d48362007-07-17 11:52:24 +02001712static void stac92xx_set_config_reg(struct hda_codec *codec,
1713 hda_nid_t pin_nid, unsigned int pin_config)
1714{
1715 int i;
1716 snd_hda_codec_write(codec, pin_nid, 0,
1717 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1718 pin_config & 0x000000ff);
1719 snd_hda_codec_write(codec, pin_nid, 0,
1720 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1721 (pin_config & 0x0000ff00) >> 8);
1722 snd_hda_codec_write(codec, pin_nid, 0,
1723 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1724 (pin_config & 0x00ff0000) >> 16);
1725 snd_hda_codec_write(codec, pin_nid, 0,
1726 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1727 pin_config >> 24);
1728 i = snd_hda_codec_read(codec, pin_nid, 0,
1729 AC_VERB_GET_CONFIG_DEFAULT,
1730 0x00);
1731 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1732 pin_nid, i);
1733}
1734
Matt2f2f4252005-04-13 14:45:30 +02001735static void stac92xx_set_config_regs(struct hda_codec *codec)
1736{
1737 int i;
1738 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001739
Matthew Ranostay87d48362007-07-17 11:52:24 +02001740 if (!spec->pin_configs)
1741 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001742
Matthew Ranostay87d48362007-07-17 11:52:24 +02001743 for (i = 0; i < spec->num_pins; i++)
1744 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1745 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001746}
Matt2f2f4252005-04-13 14:45:30 +02001747
Matt2f2f4252005-04-13 14:45:30 +02001748/*
1749 * Analog playback callbacks
1750 */
1751static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1752 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001753 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001754{
1755 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001756 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1757 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001758}
1759
1760static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1761 struct hda_codec *codec,
1762 unsigned int stream_tag,
1763 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001764 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001765{
1766 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001767 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001768}
1769
1770static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1771 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001772 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001773{
1774 struct sigmatel_spec *spec = codec->spec;
1775 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1776}
1777
1778/*
Mattdabbed62005-06-14 10:19:34 +02001779 * Digital playback callbacks
1780 */
1781static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1782 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001783 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001784{
1785 struct sigmatel_spec *spec = codec->spec;
1786 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1787}
1788
1789static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1790 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001791 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001792{
1793 struct sigmatel_spec *spec = codec->spec;
1794 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1795}
1796
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001797static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1798 struct hda_codec *codec,
1799 unsigned int stream_tag,
1800 unsigned int format,
1801 struct snd_pcm_substream *substream)
1802{
1803 struct sigmatel_spec *spec = codec->spec;
1804 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1805 stream_tag, format, substream);
1806}
1807
Mattdabbed62005-06-14 10:19:34 +02001808
1809/*
Matt2f2f4252005-04-13 14:45:30 +02001810 * Analog capture callbacks
1811 */
1812static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1813 struct hda_codec *codec,
1814 unsigned int stream_tag,
1815 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001816 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001817{
1818 struct sigmatel_spec *spec = codec->spec;
1819
1820 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1821 stream_tag, 0, format);
1822 return 0;
1823}
1824
1825static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1826 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001827 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001828{
1829 struct sigmatel_spec *spec = codec->spec;
1830
1831 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1832 return 0;
1833}
1834
Mattdabbed62005-06-14 10:19:34 +02001835static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1836 .substreams = 1,
1837 .channels_min = 2,
1838 .channels_max = 2,
1839 /* NID is set in stac92xx_build_pcms */
1840 .ops = {
1841 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001842 .close = stac92xx_dig_playback_pcm_close,
1843 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001844 },
1845};
1846
1847static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1848 .substreams = 1,
1849 .channels_min = 2,
1850 .channels_max = 2,
1851 /* NID is set in stac92xx_build_pcms */
1852};
1853
Matt2f2f4252005-04-13 14:45:30 +02001854static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1855 .substreams = 1,
1856 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001857 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001858 .nid = 0x02, /* NID to query formats and rates */
1859 .ops = {
1860 .open = stac92xx_playback_pcm_open,
1861 .prepare = stac92xx_playback_pcm_prepare,
1862 .cleanup = stac92xx_playback_pcm_cleanup
1863 },
1864};
1865
Matt Porter3cc08dc2006-01-23 15:27:49 +01001866static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1867 .substreams = 1,
1868 .channels_min = 2,
1869 .channels_max = 2,
1870 .nid = 0x06, /* NID to query formats and rates */
1871 .ops = {
1872 .open = stac92xx_playback_pcm_open,
1873 .prepare = stac92xx_playback_pcm_prepare,
1874 .cleanup = stac92xx_playback_pcm_cleanup
1875 },
1876};
1877
Matt2f2f4252005-04-13 14:45:30 +02001878static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001879 .channels_min = 2,
1880 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001881 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001882 .ops = {
1883 .prepare = stac92xx_capture_pcm_prepare,
1884 .cleanup = stac92xx_capture_pcm_cleanup
1885 },
1886};
1887
1888static int stac92xx_build_pcms(struct hda_codec *codec)
1889{
1890 struct sigmatel_spec *spec = codec->spec;
1891 struct hda_pcm *info = spec->pcm_rec;
1892
1893 codec->num_pcms = 1;
1894 codec->pcm_info = info;
1895
Mattc7d4b2f2005-06-27 14:59:41 +02001896 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02001897 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02001898 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001899 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001900 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01001901
1902 if (spec->alt_switch) {
1903 codec->num_pcms++;
1904 info++;
1905 info->name = "STAC92xx Analog Alt";
1906 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
1907 }
Matt2f2f4252005-04-13 14:45:30 +02001908
Mattdabbed62005-06-14 10:19:34 +02001909 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1910 codec->num_pcms++;
1911 info++;
1912 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01001913 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02001914 if (spec->multiout.dig_out_nid) {
1915 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
1916 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1917 }
1918 if (spec->dig_in_nid) {
1919 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
1920 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1921 }
1922 }
1923
Matt2f2f4252005-04-13 14:45:30 +02001924 return 0;
1925}
1926
Takashi Iwaic960a032006-03-23 17:06:28 +01001927static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
1928{
1929 unsigned int pincap = snd_hda_param_read(codec, nid,
1930 AC_PAR_PIN_CAP);
1931 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
1932 if (pincap & AC_PINCAP_VREF_100)
1933 return AC_PINCTL_VREF_100;
1934 if (pincap & AC_PINCAP_VREF_80)
1935 return AC_PINCTL_VREF_80;
1936 if (pincap & AC_PINCAP_VREF_50)
1937 return AC_PINCTL_VREF_50;
1938 if (pincap & AC_PINCAP_VREF_GRD)
1939 return AC_PINCTL_VREF_GRD;
1940 return 0;
1941}
1942
Matt Porter403d1942005-11-29 15:00:51 +01001943static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
1944
1945{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001946 snd_hda_codec_write_cache(codec, nid, 0,
1947 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01001948}
1949
Takashi Iwaia5ce8892007-07-23 15:42:26 +02001950#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01001951
1952static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1953{
1954 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1955 struct sigmatel_spec *spec = codec->spec;
1956 int io_idx = kcontrol-> private_value & 0xff;
1957
1958 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
1959 return 0;
1960}
1961
1962static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1963{
1964 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1965 struct sigmatel_spec *spec = codec->spec;
1966 hda_nid_t nid = kcontrol->private_value >> 8;
1967 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001968 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01001969
1970 spec->io_switch[io_idx] = val;
1971
1972 if (val)
1973 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01001974 else {
1975 unsigned int pinctl = AC_PINCTL_IN_EN;
1976 if (io_idx) /* set VREF for mic */
1977 pinctl |= stac92xx_get_vref(codec, nid);
1978 stac92xx_auto_set_pinctl(codec, nid, pinctl);
1979 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01001980
1981 /* check the auto-mute again: we need to mute/unmute the speaker
1982 * appropriately according to the pin direction
1983 */
1984 if (spec->hp_detect)
1985 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
1986
Matt Porter403d1942005-11-29 15:00:51 +01001987 return 1;
1988}
1989
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02001990#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
1991
1992static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
1993 struct snd_ctl_elem_value *ucontrol)
1994{
1995 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1996 struct sigmatel_spec *spec = codec->spec;
1997
1998 ucontrol->value.integer.value[0] = spec->clfe_swap;
1999 return 0;
2000}
2001
2002static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2003 struct snd_ctl_elem_value *ucontrol)
2004{
2005 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2006 struct sigmatel_spec *spec = codec->spec;
2007 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002008 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002009
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002010 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002011 return 0;
2012
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002013 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002014
2015 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2016 spec->clfe_swap ? 0x4 : 0x0);
2017
2018 return 1;
2019}
2020
Matt Porter403d1942005-11-29 15:00:51 +01002021#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2022 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2023 .name = xname, \
2024 .index = 0, \
2025 .info = stac92xx_io_switch_info, \
2026 .get = stac92xx_io_switch_get, \
2027 .put = stac92xx_io_switch_put, \
2028 .private_value = xpval, \
2029 }
2030
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002031#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2032 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2033 .name = xname, \
2034 .index = 0, \
2035 .info = stac92xx_clfe_switch_info, \
2036 .get = stac92xx_clfe_switch_get, \
2037 .put = stac92xx_clfe_switch_put, \
2038 .private_value = xpval, \
2039 }
Matt Porter403d1942005-11-29 15:00:51 +01002040
Mattc7d4b2f2005-06-27 14:59:41 +02002041enum {
2042 STAC_CTL_WIDGET_VOL,
2043 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002044 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002045 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002046 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002047};
2048
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002049static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002050 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2051 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002052 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002053 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002054 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002055};
2056
2057/* add dynamic controls */
2058static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2059{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002060 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002061
2062 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2063 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2064
2065 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2066 if (! knew)
2067 return -ENOMEM;
2068 if (spec->kctl_alloc) {
2069 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2070 kfree(spec->kctl_alloc);
2071 }
2072 spec->kctl_alloc = knew;
2073 spec->num_kctl_alloc = num;
2074 }
2075
2076 knew = &spec->kctl_alloc[spec->num_kctl_used];
2077 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002078 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002079 if (! knew->name)
2080 return -ENOMEM;
2081 knew->private_value = val;
2082 spec->num_kctl_used++;
2083 return 0;
2084}
2085
Matt Porter403d1942005-11-29 15:00:51 +01002086/* flag inputs as additional dynamic lineouts */
2087static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2088{
2089 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002090 unsigned int wcaps, wtype;
2091 int i, num_dacs = 0;
2092
2093 /* use the wcaps cache to count all DACs available for line-outs */
2094 for (i = 0; i < codec->num_nodes; i++) {
2095 wcaps = codec->wcaps[i];
2096 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002097
Steve Longerbeam7b043892007-05-03 20:50:03 +02002098 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2099 num_dacs++;
2100 }
Matt Porter403d1942005-11-29 15:00:51 +01002101
Steve Longerbeam7b043892007-05-03 20:50:03 +02002102 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2103
Matt Porter403d1942005-11-29 15:00:51 +01002104 switch (cfg->line_outs) {
2105 case 3:
2106 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002107 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002108 cfg->line_out_pins[cfg->line_outs] =
2109 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002110 spec->line_switch = 1;
2111 cfg->line_outs++;
2112 }
2113 break;
2114 case 2:
2115 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002116 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002117 cfg->line_out_pins[cfg->line_outs] =
2118 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002119 spec->line_switch = 1;
2120 cfg->line_outs++;
2121 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002122 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002123 cfg->line_out_pins[cfg->line_outs] =
2124 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002125 spec->mic_switch = 1;
2126 cfg->line_outs++;
2127 }
2128 break;
2129 case 1:
2130 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002131 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002132 cfg->line_out_pins[cfg->line_outs] =
2133 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002134 spec->line_switch = 1;
2135 cfg->line_outs++;
2136 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002137 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002138 cfg->line_out_pins[cfg->line_outs] =
2139 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002140 spec->mic_switch = 1;
2141 cfg->line_outs++;
2142 }
2143 break;
2144 }
2145
2146 return 0;
2147}
2148
Steve Longerbeam7b043892007-05-03 20:50:03 +02002149
2150static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2151{
2152 int i;
2153
2154 for (i = 0; i < spec->multiout.num_dacs; i++) {
2155 if (spec->multiout.dac_nids[i] == nid)
2156 return 1;
2157 }
2158
2159 return 0;
2160}
2161
Matt Porter3cc08dc2006-01-23 15:27:49 +01002162/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002163 * Fill in the dac_nids table from the parsed pin configuration
2164 * This function only works when every pin in line_out_pins[]
2165 * contains atleast one DAC in its connection list. Some 92xx
2166 * codecs are not connected directly to a DAC, such as the 9200
2167 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002168 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002169static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002170 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002171{
2172 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002173 int i, j, conn_len = 0;
2174 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2175 unsigned int wcaps, wtype;
2176
Mattc7d4b2f2005-06-27 14:59:41 +02002177 for (i = 0; i < cfg->line_outs; i++) {
2178 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002179 conn_len = snd_hda_get_connections(codec, nid, conn,
2180 HDA_MAX_CONNECTIONS);
2181 for (j = 0; j < conn_len; j++) {
2182 wcaps = snd_hda_param_read(codec, conn[j],
2183 AC_PAR_AUDIO_WIDGET_CAP);
2184 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002185 if (wtype != AC_WID_AUD_OUT ||
2186 (wcaps & AC_WCAP_DIGITAL))
2187 continue;
2188 /* conn[j] is a DAC routed to this line-out */
2189 if (!is_in_dac_nids(spec, conn[j]))
2190 break;
2191 }
2192
2193 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002194 if (spec->multiout.num_dacs > 0) {
2195 /* we have already working output pins,
2196 * so let's drop the broken ones again
2197 */
2198 cfg->line_outs = spec->multiout.num_dacs;
2199 break;
2200 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002201 /* error out, no available DAC found */
2202 snd_printk(KERN_ERR
2203 "%s: No available DAC for pin 0x%x\n",
2204 __func__, nid);
2205 return -ENODEV;
2206 }
2207
2208 spec->multiout.dac_nids[i] = conn[j];
2209 spec->multiout.num_dacs++;
2210 if (conn_len > 1) {
2211 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002212 snd_hda_codec_write_cache(codec, nid, 0,
2213 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002214
2215 }
Mattc7d4b2f2005-06-27 14:59:41 +02002216 }
2217
Steve Longerbeam7b043892007-05-03 20:50:03 +02002218 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2219 spec->multiout.num_dacs,
2220 spec->multiout.dac_nids[0],
2221 spec->multiout.dac_nids[1],
2222 spec->multiout.dac_nids[2],
2223 spec->multiout.dac_nids[3],
2224 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002225 return 0;
2226}
2227
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002228/* create volume control/switch for the given prefx type */
2229static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2230{
2231 char name[32];
2232 int err;
2233
2234 sprintf(name, "%s Playback Volume", pfx);
2235 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2236 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2237 if (err < 0)
2238 return err;
2239 sprintf(name, "%s Playback Switch", pfx);
2240 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2241 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2242 if (err < 0)
2243 return err;
2244 return 0;
2245}
2246
Mattc7d4b2f2005-06-27 14:59:41 +02002247/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002248static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002249 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002250{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002251 static const char *chname[4] = {
2252 "Front", "Surround", NULL /*CLFE*/, "Side"
2253 };
Mattc7d4b2f2005-06-27 14:59:41 +02002254 hda_nid_t nid;
2255 int i, err;
2256
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002257 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002258 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002259
2260
Mattc7d4b2f2005-06-27 14:59:41 +02002261 for (i = 0; i < cfg->line_outs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002262 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002263 continue;
2264
2265 nid = spec->multiout.dac_nids[i];
2266
2267 if (i == 2) {
2268 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002269 err = create_controls(spec, "Center", nid, 1);
2270 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002271 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002272 err = create_controls(spec, "LFE", nid, 2);
2273 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002274 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002275
2276 wid_caps = get_wcaps(codec, nid);
2277
2278 if (wid_caps & AC_WCAP_LR_SWAP) {
2279 err = stac92xx_add_control(spec,
2280 STAC_CTL_WIDGET_CLFE_SWITCH,
2281 "Swap Center/LFE Playback Switch", nid);
2282
2283 if (err < 0)
2284 return err;
2285 }
2286
Mattc7d4b2f2005-06-27 14:59:41 +02002287 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002288 err = create_controls(spec, chname[i], nid, 3);
2289 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002290 return err;
2291 }
2292 }
2293
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002294 if (spec->line_switch) {
2295 nid = cfg->input_pins[AUTO_PIN_LINE];
2296 pincap = snd_hda_param_read(codec, nid,
2297 AC_PAR_PIN_CAP);
2298 if (pincap & AC_PINCAP_OUT) {
2299 err = stac92xx_add_control(spec,
2300 STAC_CTL_WIDGET_IO_SWITCH,
2301 "Line In as Output Switch", nid << 8);
2302 if (err < 0)
2303 return err;
2304 }
2305 }
Matt Porter403d1942005-11-29 15:00:51 +01002306
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002307 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002308 unsigned int def_conf;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002309 nid = cfg->input_pins[AUTO_PIN_MIC];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002310 def_conf = snd_hda_codec_read(codec, nid, 0,
2311 AC_VERB_GET_CONFIG_DEFAULT, 0);
2312
2313 /* some laptops have an internal analog microphone
2314 * which can't be used as a output */
2315 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2316 pincap = snd_hda_param_read(codec, nid,
2317 AC_PAR_PIN_CAP);
2318 if (pincap & AC_PINCAP_OUT) {
2319 err = stac92xx_add_control(spec,
2320 STAC_CTL_WIDGET_IO_SWITCH,
2321 "Mic as Output Switch", (nid << 8) | 1);
2322 if (err < 0)
2323 return err;
2324 }
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002325 }
2326 }
Matt Porter403d1942005-11-29 15:00:51 +01002327
Mattc7d4b2f2005-06-27 14:59:41 +02002328 return 0;
2329}
2330
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002331static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2332{
Steve Longerbeam7b043892007-05-03 20:50:03 +02002333 if (is_in_dac_nids(spec, nid))
2334 return 1;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002335 if (spec->multiout.hp_nid == nid)
2336 return 1;
2337 return 0;
2338}
2339
2340static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2341{
2342 if (!spec->multiout.hp_nid)
2343 spec->multiout.hp_nid = nid;
2344 else if (spec->multiout.num_dacs > 4) {
2345 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2346 return 1;
2347 } else {
2348 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2349 spec->multiout.num_dacs++;
2350 }
2351 return 0;
2352}
2353
2354/* add playback controls for Speaker and HP outputs */
2355static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2356 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002357{
2358 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002359 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002360 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002361
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002362 old_num_dacs = spec->multiout.num_dacs;
2363 for (i = 0; i < cfg->hp_outs; i++) {
2364 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2365 if (wid_caps & AC_WCAP_UNSOL_CAP)
2366 spec->hp_detect = 1;
2367 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2368 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2369 if (check_in_dac_nids(spec, nid))
2370 nid = 0;
2371 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002372 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002373 add_spec_dacs(spec, nid);
2374 }
2375 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002376 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002377 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2378 if (check_in_dac_nids(spec, nid))
2379 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002380 if (! nid)
2381 continue;
2382 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002383 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002384 for (i = 0; i < cfg->line_outs; i++) {
2385 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2386 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2387 if (check_in_dac_nids(spec, nid))
2388 nid = 0;
2389 if (! nid)
2390 continue;
2391 add_spec_dacs(spec, nid);
2392 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002393 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2394 static const char *pfxs[] = {
2395 "Speaker", "External Speaker", "Speaker2",
2396 };
2397 err = create_controls(spec, pfxs[i - old_num_dacs],
2398 spec->multiout.dac_nids[i], 3);
2399 if (err < 0)
2400 return err;
2401 }
2402 if (spec->multiout.hp_nid) {
2403 const char *pfx;
Takashi Iwai6020c002007-11-19 11:56:26 +01002404 if (old_num_dacs == spec->multiout.num_dacs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002405 pfx = "Master";
2406 else
2407 pfx = "Headphone";
2408 err = create_controls(spec, pfx, spec->multiout.hp_nid, 3);
2409 if (err < 0)
2410 return err;
2411 }
Mattc7d4b2f2005-06-27 14:59:41 +02002412
2413 return 0;
2414}
2415
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002416/* labels for mono mux outputs */
2417static const char *stac92xx_mono_labels[3] = {
2418 "DAC0", "DAC1", "Mixer"
2419};
2420
2421/* create mono mux for mono out on capable codecs */
2422static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2423{
2424 struct sigmatel_spec *spec = codec->spec;
2425 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2426 int i, num_cons;
2427 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2428
2429 num_cons = snd_hda_get_connections(codec,
2430 spec->mono_nid,
2431 con_lst,
2432 HDA_MAX_NUM_INPUTS);
2433 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2434 return -EINVAL;
2435
2436 for (i = 0; i < num_cons; i++) {
2437 mono_mux->items[mono_mux->num_items].label =
2438 stac92xx_mono_labels[i];
2439 mono_mux->items[mono_mux->num_items].index = i;
2440 mono_mux->num_items++;
2441 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002442
2443 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2444 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002445}
2446
Matt Porter8b657272006-10-26 17:12:59 +02002447/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002448static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002449 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2450 "Digital Mic 3", "Digital Mic 4"
2451};
2452
2453/* create playback/capture controls for input pins on dmic capable codecs */
2454static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2455 const struct auto_pin_cfg *cfg)
2456{
2457 struct sigmatel_spec *spec = codec->spec;
2458 struct hda_input_mux *dimux = &spec->private_dimux;
2459 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002460 int err, i, j;
2461 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002462
2463 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2464 dimux->items[dimux->num_items].index = 0;
2465 dimux->num_items++;
2466
2467 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002468 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002469 int index;
2470 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002471 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002472 unsigned int def_conf;
2473
2474 def_conf = snd_hda_codec_read(codec,
2475 spec->dmic_nids[i],
2476 0,
2477 AC_VERB_GET_CONFIG_DEFAULT,
2478 0);
2479 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2480 continue;
2481
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002482 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002483 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002484 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002485 con_lst,
2486 HDA_MAX_NUM_INPUTS);
2487 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002488 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002489 index = j;
2490 goto found;
2491 }
2492 continue;
2493found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002494 wcaps = get_wcaps(codec, nid);
2495
2496 if (wcaps & AC_WCAP_OUT_AMP) {
2497 sprintf(name, "%s Capture Volume",
2498 stac92xx_dmic_labels[dimux->num_items]);
2499
2500 err = stac92xx_add_control(spec,
2501 STAC_CTL_WIDGET_VOL,
2502 name,
2503 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2504 if (err < 0)
2505 return err;
2506 }
2507
Matt Porter8b657272006-10-26 17:12:59 +02002508 dimux->items[dimux->num_items].label =
2509 stac92xx_dmic_labels[dimux->num_items];
2510 dimux->items[dimux->num_items].index = index;
2511 dimux->num_items++;
2512 }
2513
2514 return 0;
2515}
2516
Mattc7d4b2f2005-06-27 14:59:41 +02002517/* create playback/capture controls for input pins */
2518static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2519{
2520 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002521 struct hda_input_mux *imux = &spec->private_imux;
2522 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2523 int i, j, k;
2524
2525 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002526 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002527
Takashi Iwai314634b2006-09-21 11:56:18 +02002528 if (!cfg->input_pins[i])
2529 continue;
2530 index = -1;
2531 for (j = 0; j < spec->num_muxes; j++) {
2532 int num_cons;
2533 num_cons = snd_hda_get_connections(codec,
2534 spec->mux_nids[j],
2535 con_lst,
2536 HDA_MAX_NUM_INPUTS);
2537 for (k = 0; k < num_cons; k++)
2538 if (con_lst[k] == cfg->input_pins[i]) {
2539 index = k;
2540 goto found;
2541 }
Mattc7d4b2f2005-06-27 14:59:41 +02002542 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002543 continue;
2544 found:
2545 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2546 imux->items[imux->num_items].index = index;
2547 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002548 }
2549
Steve Longerbeam7b043892007-05-03 20:50:03 +02002550 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002551 /*
2552 * Set the current input for the muxes.
2553 * The STAC9221 has two input muxes with identical source
2554 * NID lists. Hopefully this won't get confused.
2555 */
2556 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002557 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2558 AC_VERB_SET_CONNECT_SEL,
2559 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002560 }
2561 }
2562
Mattc7d4b2f2005-06-27 14:59:41 +02002563 return 0;
2564}
2565
Mattc7d4b2f2005-06-27 14:59:41 +02002566static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2567{
2568 struct sigmatel_spec *spec = codec->spec;
2569 int i;
2570
2571 for (i = 0; i < spec->autocfg.line_outs; i++) {
2572 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2573 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2574 }
2575}
2576
2577static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2578{
2579 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002580 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002581
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002582 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2583 hda_nid_t pin;
2584 pin = spec->autocfg.hp_pins[i];
2585 if (pin) /* connect to front */
2586 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2587 }
2588 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2589 hda_nid_t pin;
2590 pin = spec->autocfg.speaker_pins[i];
2591 if (pin) /* connect to front */
2592 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2593 }
Mattc7d4b2f2005-06-27 14:59:41 +02002594}
2595
Matt Porter3cc08dc2006-01-23 15:27:49 +01002596static 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 +02002597{
2598 struct sigmatel_spec *spec = codec->spec;
2599 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002600 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002601
Matt Porter8b657272006-10-26 17:12:59 +02002602 if ((err = snd_hda_parse_pin_def_config(codec,
2603 &spec->autocfg,
2604 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002605 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002606 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002607 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002608
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002609 /* If we have no real line-out pin and multiple hp-outs, HPs should
2610 * be set up as multi-channel outputs.
2611 */
2612 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2613 spec->autocfg.hp_outs > 1) {
2614 /* Copy hp_outs to line_outs, backup line_outs in
2615 * speaker_outs so that the following routines can handle
2616 * HP pins as primary outputs.
2617 */
2618 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2619 sizeof(spec->autocfg.line_out_pins));
2620 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2621 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2622 sizeof(spec->autocfg.hp_pins));
2623 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2624 hp_speaker_swap = 1;
2625 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002626 if (spec->autocfg.mono_out_pin) {
2627 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2628 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2629 u32 caps = query_amp_caps(codec,
2630 spec->autocfg.mono_out_pin, dir);
2631 hda_nid_t conn_list[1];
2632
2633 /* get the mixer node and then the mono mux if it exists */
2634 if (snd_hda_get_connections(codec,
2635 spec->autocfg.mono_out_pin, conn_list, 1) &&
2636 snd_hda_get_connections(codec, conn_list[0],
2637 conn_list, 1)) {
2638
2639 int wcaps = get_wcaps(codec, conn_list[0]);
2640 int wid_type = (wcaps & AC_WCAP_TYPE)
2641 >> AC_WCAP_TYPE_SHIFT;
2642 /* LR swap check, some stac925x have a mux that
2643 * changes the DACs output path instead of the
2644 * mono-mux path.
2645 */
2646 if (wid_type == AC_WID_AUD_SEL &&
2647 !(wcaps & AC_WCAP_LR_SWAP))
2648 spec->mono_nid = conn_list[0];
2649 }
2650 /* all mono outs have a least a mute/unmute switch */
2651 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2652 "Mono Playback Switch",
2653 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2654 1, 0, dir));
2655 if (err < 0)
2656 return err;
2657 /* check to see if there is volume support for the amp */
2658 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2659 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2660 "Mono Playback Volume",
2661 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2662 1, 0, dir));
2663 if (err < 0)
2664 return err;
2665 }
2666
2667 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2668 AC_PINCTL_OUT_EN);
2669 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002670
Matt Porter403d1942005-11-29 15:00:51 +01002671 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2672 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002673 if (spec->multiout.num_dacs == 0)
2674 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2675 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002676
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002677 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2678
2679 if (err < 0)
2680 return err;
2681
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002682 if (hp_speaker_swap == 1) {
2683 /* Restore the hp_outs and line_outs */
2684 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2685 sizeof(spec->autocfg.line_out_pins));
2686 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2687 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2688 sizeof(spec->autocfg.speaker_pins));
2689 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2690 memset(spec->autocfg.speaker_pins, 0,
2691 sizeof(spec->autocfg.speaker_pins));
2692 spec->autocfg.speaker_outs = 0;
2693 }
2694
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002695 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2696
2697 if (err < 0)
2698 return err;
2699
2700 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2701
2702 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002703 return err;
2704
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002705 if (spec->mono_nid > 0) {
2706 err = stac92xx_auto_create_mono_output_ctls(codec);
2707 if (err < 0)
2708 return err;
2709 }
2710
Matt Porter8b657272006-10-26 17:12:59 +02002711 if (spec->num_dmics > 0)
2712 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2713 &spec->autocfg)) < 0)
2714 return err;
2715
Mattc7d4b2f2005-06-27 14:59:41 +02002716 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002717 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002718 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002719
Takashi Iwai82bc9552006-03-21 11:24:42 +01002720 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002721 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002722 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002723 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002724
2725 if (spec->kctl_alloc)
2726 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2727
2728 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002729 if (!spec->dinput_mux)
2730 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002731 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002732
2733 return 1;
2734}
2735
Takashi Iwai82bc9552006-03-21 11:24:42 +01002736/* add playback controls for HP output */
2737static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2738 struct auto_pin_cfg *cfg)
2739{
2740 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002741 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002742 unsigned int wid_caps;
2743
2744 if (! pin)
2745 return 0;
2746
2747 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002748 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002749 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002750
2751 return 0;
2752}
2753
Richard Fish160ea0d2006-09-06 13:58:25 +02002754/* add playback controls for LFE output */
2755static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2756 struct auto_pin_cfg *cfg)
2757{
2758 struct sigmatel_spec *spec = codec->spec;
2759 int err;
2760 hda_nid_t lfe_pin = 0x0;
2761 int i;
2762
2763 /*
2764 * search speaker outs and line outs for a mono speaker pin
2765 * with an amp. If one is found, add LFE controls
2766 * for it.
2767 */
2768 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2769 hda_nid_t pin = spec->autocfg.speaker_pins[i];
2770 unsigned long wcaps = get_wcaps(codec, pin);
2771 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2772 if (wcaps == AC_WCAP_OUT_AMP)
2773 /* found a mono speaker with an amp, must be lfe */
2774 lfe_pin = pin;
2775 }
2776
2777 /* if speaker_outs is 0, then speakers may be in line_outs */
2778 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2779 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2780 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2781 unsigned long cfg;
2782 cfg = snd_hda_codec_read(codec, pin, 0,
2783 AC_VERB_GET_CONFIG_DEFAULT,
2784 0x00);
2785 if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) {
2786 unsigned long wcaps = get_wcaps(codec, pin);
2787 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2788 if (wcaps == AC_WCAP_OUT_AMP)
2789 /* found a mono speaker with an amp,
2790 must be lfe */
2791 lfe_pin = pin;
2792 }
2793 }
2794 }
2795
2796 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002797 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002798 if (err < 0)
2799 return err;
2800 }
2801
2802 return 0;
2803}
2804
Mattc7d4b2f2005-06-27 14:59:41 +02002805static int stac9200_parse_auto_config(struct hda_codec *codec)
2806{
2807 struct sigmatel_spec *spec = codec->spec;
2808 int err;
2809
Kailang Yangdf694da2005-12-05 19:42:22 +01002810 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002811 return err;
2812
2813 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2814 return err;
2815
Takashi Iwai82bc9552006-03-21 11:24:42 +01002816 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2817 return err;
2818
Richard Fish160ea0d2006-09-06 13:58:25 +02002819 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2820 return err;
2821
Takashi Iwai82bc9552006-03-21 11:24:42 +01002822 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002823 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002824 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002825 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002826
2827 if (spec->kctl_alloc)
2828 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2829
2830 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002831 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002832
2833 return 1;
2834}
2835
Sam Revitch62fe78e2006-05-10 15:09:17 +02002836/*
2837 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2838 * funky external mute control using GPIO pins.
2839 */
2840
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002841static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002842 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002843{
2844 unsigned int gpiostate, gpiomask, gpiodir;
2845
2846 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2847 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002848 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002849
2850 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2851 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002852 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002853
2854 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2855 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002856 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002857
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002858 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002859 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2860
2861 snd_hda_codec_write(codec, codec->afg, 0,
2862 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002863 snd_hda_codec_read(codec, codec->afg, 0,
2864 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002865
2866 msleep(1);
2867
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002868 snd_hda_codec_read(codec, codec->afg, 0,
2869 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002870}
2871
Takashi Iwai314634b2006-09-21 11:56:18 +02002872static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2873 unsigned int event)
2874{
2875 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002876 snd_hda_codec_write_cache(codec, nid, 0,
2877 AC_VERB_SET_UNSOLICITED_ENABLE,
2878 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002879}
2880
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002881static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2882{
2883 int i;
2884 for (i = 0; i < cfg->hp_outs; i++)
2885 if (cfg->hp_pins[i] == nid)
2886 return 1; /* nid is a HP-Out */
2887
2888 return 0; /* nid is not a HP-Out */
2889};
2890
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002891static void stac92xx_power_down(struct hda_codec *codec)
2892{
2893 struct sigmatel_spec *spec = codec->spec;
2894
2895 /* power down inactive DACs */
2896 hda_nid_t *dac;
2897 for (dac = spec->dac_list; *dac; dac++)
2898 if (!is_in_dac_nids(spec, *dac))
2899 snd_hda_codec_write_cache(codec, *dac, 0,
2900 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
2901}
2902
Mattc7d4b2f2005-06-27 14:59:41 +02002903static int stac92xx_init(struct hda_codec *codec)
2904{
2905 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002906 struct auto_pin_cfg *cfg = &spec->autocfg;
2907 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002908
Mattc7d4b2f2005-06-27 14:59:41 +02002909 snd_hda_sequence_write(codec, spec->init);
2910
Takashi Iwai82bc9552006-03-21 11:24:42 +01002911 /* set up pins */
2912 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02002913 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002914 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02002915 enable_pin_detect(codec, cfg->hp_pins[i],
2916 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01002917 /* force to enable the first line-out; the others are set up
2918 * in unsol_event
2919 */
2920 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
2921 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02002922 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002923 /* fake event to set up pins */
2924 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2925 } else {
2926 stac92xx_auto_init_multi_out(codec);
2927 stac92xx_auto_init_hp_out(codec);
2928 }
2929 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01002930 hda_nid_t nid = cfg->input_pins[i];
2931 if (nid) {
2932 unsigned int pinctl = AC_PINCTL_IN_EN;
2933 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
2934 pinctl |= stac92xx_get_vref(codec, nid);
2935 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2936 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01002937 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002938 for (i = 0; i < spec->num_dmics; i++)
2939 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
2940 AC_PINCTL_IN_EN);
2941 for (i = 0; i < spec->num_pwrs; i++) {
2942 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
2943 ? STAC_HP_EVENT : STAC_PWR_EVENT;
2944 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
2945 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2946 /* outputs are only ports capable of power management
2947 * any attempts on powering down a input port cause the
2948 * referenced VREF to act quirky.
2949 */
2950 if (pinctl & AC_PINCTL_IN_EN)
2951 continue;
2952 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
2953 codec->patch_ops.unsol_event(codec, (event | i) << 26);
2954 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01002955 if (spec->dac_list)
2956 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01002957 if (cfg->dig_out_pin)
2958 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
2959 AC_PINCTL_OUT_EN);
2960 if (cfg->dig_in_pin)
2961 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
2962 AC_PINCTL_IN_EN);
2963
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002964 stac_gpio_set(codec, spec->gpio_mask,
2965 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002966
Mattc7d4b2f2005-06-27 14:59:41 +02002967 return 0;
2968}
2969
Matt2f2f4252005-04-13 14:45:30 +02002970static void stac92xx_free(struct hda_codec *codec)
2971{
Mattc7d4b2f2005-06-27 14:59:41 +02002972 struct sigmatel_spec *spec = codec->spec;
2973 int i;
2974
2975 if (! spec)
2976 return;
2977
2978 if (spec->kctl_alloc) {
2979 for (i = 0; i < spec->num_kctl_used; i++)
2980 kfree(spec->kctl_alloc[i].name);
2981 kfree(spec->kctl_alloc);
2982 }
2983
Richard Fish11b44bb2006-08-23 18:31:34 +02002984 if (spec->bios_pin_configs)
2985 kfree(spec->bios_pin_configs);
2986
Mattc7d4b2f2005-06-27 14:59:41 +02002987 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02002988}
2989
Matt4e550962005-07-04 17:51:39 +02002990static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
2991 unsigned int flag)
2992{
2993 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
2994 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002995
Takashi Iwaif9acba42007-05-29 18:01:06 +02002996 if (pin_ctl & AC_PINCTL_IN_EN) {
2997 /*
2998 * we need to check the current set-up direction of
2999 * shared input pins since they can be switched via
3000 * "xxx as Output" mixer switch
3001 */
3002 struct sigmatel_spec *spec = codec->spec;
3003 struct auto_pin_cfg *cfg = &spec->autocfg;
3004 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3005 spec->line_switch) ||
3006 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3007 spec->mic_switch))
3008 return;
3009 }
3010
Steve Longerbeam7b043892007-05-03 20:50:03 +02003011 /* if setting pin direction bits, clear the current
3012 direction bits first */
3013 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3014 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3015
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003016 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003017 AC_VERB_SET_PIN_WIDGET_CONTROL,
3018 pin_ctl | flag);
3019}
3020
3021static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3022 unsigned int flag)
3023{
3024 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3025 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003026 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003027 AC_VERB_SET_PIN_WIDGET_CONTROL,
3028 pin_ctl & ~flag);
3029}
3030
Jiang Zhe40c1d302007-11-12 13:05:16 +01003031static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003032{
3033 if (!nid)
3034 return 0;
3035 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003036 & (1 << 31)) {
3037 unsigned int pinctl;
3038 pinctl = snd_hda_codec_read(codec, nid, 0,
3039 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3040 if (pinctl & AC_PINCTL_IN_EN)
3041 return 0; /* mic- or line-input */
3042 else
3043 return 1; /* HP-output */
3044 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003045 return 0;
3046}
3047
3048static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003049{
3050 struct sigmatel_spec *spec = codec->spec;
3051 struct auto_pin_cfg *cfg = &spec->autocfg;
3052 int i, presence;
3053
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003054 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003055 if (spec->gpio_mute)
3056 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3057 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3058
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003059 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003060 if (presence)
3061 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003062 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003063 }
Matt4e550962005-07-04 17:51:39 +02003064
3065 if (presence) {
3066 /* disable lineouts, enable hp */
3067 for (i = 0; i < cfg->line_outs; i++)
3068 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3069 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003070 for (i = 0; i < cfg->speaker_outs; i++)
3071 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3072 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003073 } else {
3074 /* enable lineouts, disable hp */
3075 for (i = 0; i < cfg->line_outs; i++)
3076 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3077 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003078 for (i = 0; i < cfg->speaker_outs; i++)
3079 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3080 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003081 }
3082}
3083
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003084static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3085{
3086 struct sigmatel_spec *spec = codec->spec;
3087 hda_nid_t nid = spec->pwr_nids[idx];
3088 int presence, val;
3089 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3090 & 0x000000ff;
3091 presence = get_hp_pin_presence(codec, nid);
3092 idx = 1 << idx;
3093
3094 if (presence)
3095 val &= ~idx;
3096 else
3097 val |= idx;
3098
3099 /* power down unused output ports */
3100 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3101};
3102
Takashi Iwai314634b2006-09-21 11:56:18 +02003103static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3104{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003105 struct sigmatel_spec *spec = codec->spec;
3106 int idx = res >> 26 & 0x0f;
3107
3108 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003109 case STAC_HP_EVENT:
3110 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003111 /* fallthru */
3112 case STAC_PWR_EVENT:
3113 if (spec->num_pwrs > 0)
3114 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003115 }
3116}
3117
Takashi Iwaicb53c622007-08-10 17:21:45 +02003118#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003119static int stac92xx_resume(struct hda_codec *codec)
3120{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003121 struct sigmatel_spec *spec = codec->spec;
3122
Richard Fish11b44bb2006-08-23 18:31:34 +02003123 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003124 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003125 stac_gpio_set(codec, spec->gpio_mask,
3126 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003127 snd_hda_codec_resume_amp(codec);
3128 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003129 /* power down inactive DACs */
3130 if (spec->dac_list)
3131 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003132 /* invoke unsolicited event to reset the HP state */
3133 if (spec->hp_detect)
3134 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003135 return 0;
3136}
3137#endif
3138
Matt2f2f4252005-04-13 14:45:30 +02003139static struct hda_codec_ops stac92xx_patch_ops = {
3140 .build_controls = stac92xx_build_controls,
3141 .build_pcms = stac92xx_build_pcms,
3142 .init = stac92xx_init,
3143 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003144 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003145#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003146 .resume = stac92xx_resume,
3147#endif
Matt2f2f4252005-04-13 14:45:30 +02003148};
3149
3150static int patch_stac9200(struct hda_codec *codec)
3151{
3152 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003153 int err;
Matt2f2f4252005-04-13 14:45:30 +02003154
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003155 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003156 if (spec == NULL)
3157 return -ENOMEM;
3158
3159 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003160 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003161 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003162 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3163 stac9200_models,
3164 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003165 if (spec->board_config < 0) {
3166 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3167 err = stac92xx_save_bios_config_regs(codec);
3168 if (err < 0) {
3169 stac92xx_free(codec);
3170 return err;
3171 }
3172 spec->pin_configs = spec->bios_pin_configs;
3173 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003174 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3175 stac92xx_set_config_regs(codec);
3176 }
Matt2f2f4252005-04-13 14:45:30 +02003177
3178 spec->multiout.max_channels = 2;
3179 spec->multiout.num_dacs = 1;
3180 spec->multiout.dac_nids = stac9200_dac_nids;
3181 spec->adc_nids = stac9200_adc_nids;
3182 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003183 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003184 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003185 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003186 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003187
Tobin Davisbf277782008-02-03 20:31:47 +01003188 if (spec->board_config == STAC_9200_GATEWAY ||
3189 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003190 spec->init = stac9200_eapd_init;
3191 else
3192 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003193 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003194
3195 err = stac9200_parse_auto_config(codec);
3196 if (err < 0) {
3197 stac92xx_free(codec);
3198 return err;
3199 }
Matt2f2f4252005-04-13 14:45:30 +02003200
3201 codec->patch_ops = stac92xx_patch_ops;
3202
3203 return 0;
3204}
3205
Tobin Davis8e21c342007-01-08 11:04:17 +01003206static int patch_stac925x(struct hda_codec *codec)
3207{
3208 struct sigmatel_spec *spec;
3209 int err;
3210
3211 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3212 if (spec == NULL)
3213 return -ENOMEM;
3214
3215 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003216 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003217 spec->pin_nids = stac925x_pin_nids;
3218 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3219 stac925x_models,
3220 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003221 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003222 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003223 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3224 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003225 err = stac92xx_save_bios_config_regs(codec);
3226 if (err < 0) {
3227 stac92xx_free(codec);
3228 return err;
3229 }
3230 spec->pin_configs = spec->bios_pin_configs;
3231 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3232 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3233 stac92xx_set_config_regs(codec);
3234 }
3235
3236 spec->multiout.max_channels = 2;
3237 spec->multiout.num_dacs = 1;
3238 spec->multiout.dac_nids = stac925x_dac_nids;
3239 spec->adc_nids = stac925x_adc_nids;
3240 spec->mux_nids = stac925x_mux_nids;
3241 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003242 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003243 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003244 switch (codec->vendor_id) {
3245 case 0x83847632: /* STAC9202 */
3246 case 0x83847633: /* STAC9202D */
3247 case 0x83847636: /* STAC9251 */
3248 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003249 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003250 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003251 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3252 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003253 break;
3254 default:
3255 spec->num_dmics = 0;
3256 break;
3257 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003258
3259 spec->init = stac925x_core_init;
3260 spec->mixer = stac925x_mixer;
3261
3262 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003263 if (!err) {
3264 if (spec->board_config < 0) {
3265 printk(KERN_WARNING "hda_codec: No auto-config is "
3266 "available, default to model=ref\n");
3267 spec->board_config = STAC_925x_REF;
3268 goto again;
3269 }
3270 err = -EINVAL;
3271 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003272 if (err < 0) {
3273 stac92xx_free(codec);
3274 return err;
3275 }
3276
3277 codec->patch_ops = stac92xx_patch_ops;
3278
3279 return 0;
3280}
3281
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003282static struct hda_input_mux stac92hd73xx_dmux = {
3283 .num_items = 4,
3284 .items = {
3285 { "Analog Inputs", 0x0b },
3286 { "CD", 0x08 },
3287 { "Digital Mic 1", 0x09 },
3288 { "Digital Mic 2", 0x0a },
3289 }
3290};
3291
3292static int patch_stac92hd73xx(struct hda_codec *codec)
3293{
3294 struct sigmatel_spec *spec;
3295 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3296 int err = 0;
3297
3298 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3299 if (spec == NULL)
3300 return -ENOMEM;
3301
3302 codec->spec = spec;
3303 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3304 spec->pin_nids = stac92hd73xx_pin_nids;
3305 spec->board_config = snd_hda_check_board_config(codec,
3306 STAC_92HD73XX_MODELS,
3307 stac92hd73xx_models,
3308 stac92hd73xx_cfg_tbl);
3309again:
3310 if (spec->board_config < 0) {
3311 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3312 " STAC92HD73XX, using BIOS defaults\n");
3313 err = stac92xx_save_bios_config_regs(codec);
3314 if (err < 0) {
3315 stac92xx_free(codec);
3316 return err;
3317 }
3318 spec->pin_configs = spec->bios_pin_configs;
3319 } else {
3320 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3321 stac92xx_set_config_regs(codec);
3322 }
3323
3324 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3325 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3326
3327 if (spec->multiout.num_dacs < 0) {
3328 printk(KERN_WARNING "hda_codec: Could not determine "
3329 "number of channels defaulting to DAC count\n");
3330 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3331 }
3332
3333 switch (spec->multiout.num_dacs) {
3334 case 0x3: /* 6 Channel */
3335 spec->mixer = stac92hd73xx_6ch_mixer;
3336 spec->init = stac92hd73xx_6ch_core_init;
3337 break;
3338 case 0x4: /* 8 Channel */
3339 spec->multiout.hp_nid = 0x18;
3340 spec->mixer = stac92hd73xx_8ch_mixer;
3341 spec->init = stac92hd73xx_8ch_core_init;
3342 break;
3343 case 0x5: /* 10 Channel */
3344 spec->multiout.hp_nid = 0x19;
3345 spec->mixer = stac92hd73xx_10ch_mixer;
3346 spec->init = stac92hd73xx_10ch_core_init;
3347 };
3348
3349 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3350 spec->aloopback_mask = 0x01;
3351 spec->aloopback_shift = 8;
3352
3353 spec->mux_nids = stac92hd73xx_mux_nids;
3354 spec->adc_nids = stac92hd73xx_adc_nids;
3355 spec->dmic_nids = stac92hd73xx_dmic_nids;
3356 spec->dmux_nids = stac92hd73xx_dmux_nids;
3357
3358 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3359 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
3360 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003361 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003362 spec->dinput_mux = &stac92hd73xx_dmux;
3363 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003364 spec->gpio_mask = spec->gpio_dir = 0x1;
3365 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003366
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003367 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3368 spec->pwr_nids = stac92hd73xx_pwr_nids;
3369
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003370 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3371
3372 if (!err) {
3373 if (spec->board_config < 0) {
3374 printk(KERN_WARNING "hda_codec: No auto-config is "
3375 "available, default to model=ref\n");
3376 spec->board_config = STAC_92HD73XX_REF;
3377 goto again;
3378 }
3379 err = -EINVAL;
3380 }
3381
3382 if (err < 0) {
3383 stac92xx_free(codec);
3384 return err;
3385 }
3386
3387 codec->patch_ops = stac92xx_patch_ops;
3388
3389 return 0;
3390}
3391
Matthew Ranostaye035b842007-11-06 11:53:55 +01003392static int patch_stac92hd71bxx(struct hda_codec *codec)
3393{
3394 struct sigmatel_spec *spec;
3395 int err = 0;
3396
3397 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3398 if (spec == NULL)
3399 return -ENOMEM;
3400
3401 codec->spec = spec;
3402 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3403 spec->pin_nids = stac92hd71bxx_pin_nids;
3404 spec->board_config = snd_hda_check_board_config(codec,
3405 STAC_92HD71BXX_MODELS,
3406 stac92hd71bxx_models,
3407 stac92hd71bxx_cfg_tbl);
3408again:
3409 if (spec->board_config < 0) {
3410 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3411 " STAC92HD71BXX, using BIOS defaults\n");
3412 err = stac92xx_save_bios_config_regs(codec);
3413 if (err < 0) {
3414 stac92xx_free(codec);
3415 return err;
3416 }
3417 spec->pin_configs = spec->bios_pin_configs;
3418 } else {
3419 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3420 stac92xx_set_config_regs(codec);
3421 }
3422
Matthew Ranostay541eee82007-12-14 12:08:04 +01003423 switch (codec->vendor_id) {
3424 case 0x111d76b6: /* 4 Port without Analog Mixer */
3425 case 0x111d76b7:
3426 case 0x111d76b4: /* 6 Port without Analog Mixer */
3427 case 0x111d76b5:
3428 spec->mixer = stac92hd71bxx_mixer;
3429 spec->init = stac92hd71bxx_core_init;
3430 break;
3431 default:
3432 spec->mixer = stac92hd71bxx_analog_mixer;
3433 spec->init = stac92hd71bxx_analog_core_init;
3434 }
3435
3436 spec->aloopback_mask = 0x20;
3437 spec->aloopback_shift = 0;
3438
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003439 /* GPIO0 High = EAPD */
3440 spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003441
Matthew Ranostaye035b842007-11-06 11:53:55 +01003442 spec->mux_nids = stac92hd71bxx_mux_nids;
3443 spec->adc_nids = stac92hd71bxx_adc_nids;
3444 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003445 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003446
3447 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3448 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3449 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003450 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003451
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003452 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3453 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3454
Matthew Ranostaye035b842007-11-06 11:53:55 +01003455 spec->multiout.num_dacs = 2;
3456 spec->multiout.hp_nid = 0x11;
3457 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3458
3459 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3460 if (!err) {
3461 if (spec->board_config < 0) {
3462 printk(KERN_WARNING "hda_codec: No auto-config is "
3463 "available, default to model=ref\n");
3464 spec->board_config = STAC_92HD71BXX_REF;
3465 goto again;
3466 }
3467 err = -EINVAL;
3468 }
3469
3470 if (err < 0) {
3471 stac92xx_free(codec);
3472 return err;
3473 }
3474
3475 codec->patch_ops = stac92xx_patch_ops;
3476
3477 return 0;
3478};
3479
Matt2f2f4252005-04-13 14:45:30 +02003480static int patch_stac922x(struct hda_codec *codec)
3481{
3482 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003483 int err;
Matt2f2f4252005-04-13 14:45:30 +02003484
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003485 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003486 if (spec == NULL)
3487 return -ENOMEM;
3488
3489 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003490 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003491 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003492 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3493 stac922x_models,
3494 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003495 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003496 spec->gpio_mask = spec->gpio_dir = 0x03;
3497 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003498 /* Intel Macs have all same PCI SSID, so we need to check
3499 * codec SSID to distinguish the exact models
3500 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003501 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003502 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003503
3504 case 0x106b0800:
3505 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003506 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003507 case 0x106b0600:
3508 case 0x106b0700:
3509 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003510 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003511 case 0x106b0e00:
3512 case 0x106b0f00:
3513 case 0x106b1600:
3514 case 0x106b1700:
3515 case 0x106b0200:
3516 case 0x106b1e00:
3517 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003518 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003519 case 0x106b1a00:
3520 case 0x00000100:
3521 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003522 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003523 case 0x106b0a00:
3524 case 0x106b2200:
3525 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003526 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003527 }
3528 }
3529
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003530 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003531 if (spec->board_config < 0) {
3532 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3533 "using BIOS defaults\n");
3534 err = stac92xx_save_bios_config_regs(codec);
3535 if (err < 0) {
3536 stac92xx_free(codec);
3537 return err;
3538 }
3539 spec->pin_configs = spec->bios_pin_configs;
3540 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003541 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3542 stac92xx_set_config_regs(codec);
3543 }
Matt2f2f4252005-04-13 14:45:30 +02003544
Matt2f2f4252005-04-13 14:45:30 +02003545 spec->adc_nids = stac922x_adc_nids;
3546 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003547 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003548 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003549 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003550 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003551
3552 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003553 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003554
3555 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003556
Matt Porter3cc08dc2006-01-23 15:27:49 +01003557 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003558 if (!err) {
3559 if (spec->board_config < 0) {
3560 printk(KERN_WARNING "hda_codec: No auto-config is "
3561 "available, default to model=ref\n");
3562 spec->board_config = STAC_D945_REF;
3563 goto again;
3564 }
3565 err = -EINVAL;
3566 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003567 if (err < 0) {
3568 stac92xx_free(codec);
3569 return err;
3570 }
3571
3572 codec->patch_ops = stac92xx_patch_ops;
3573
Takashi Iwai807a46362007-05-29 19:01:37 +02003574 /* Fix Mux capture level; max to 2 */
3575 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3576 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3577 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3578 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3579 (0 << AC_AMPCAP_MUTE_SHIFT));
3580
Matt Porter3cc08dc2006-01-23 15:27:49 +01003581 return 0;
3582}
3583
3584static int patch_stac927x(struct hda_codec *codec)
3585{
3586 struct sigmatel_spec *spec;
3587 int err;
3588
3589 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3590 if (spec == NULL)
3591 return -ENOMEM;
3592
3593 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003594 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003595 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003596 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3597 stac927x_models,
3598 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003599 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003600 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3601 if (spec->board_config < 0)
3602 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3603 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003604 err = stac92xx_save_bios_config_regs(codec);
3605 if (err < 0) {
3606 stac92xx_free(codec);
3607 return err;
3608 }
3609 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003610 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003611 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3612 stac92xx_set_config_regs(codec);
3613 }
3614
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003615 spec->adc_nids = stac927x_adc_nids;
3616 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3617 spec->mux_nids = stac927x_mux_nids;
3618 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003619 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003620 spec->multiout.dac_nids = spec->dac_nids;
3621
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003622 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003623 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003624 case STAC_D965_5ST:
3625 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003626 spec->gpio_mask = spec->gpio_dir = 0x01;
3627 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003628 spec->num_dmics = 0;
3629
Tobin Davis93ed1502006-09-01 21:03:12 +02003630 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003631 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003632 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003633 case STAC_DELL_BIOS:
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003634 /* correct the front output jack as a hp out */
3635 stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003636 /* correct the front input jack as a mic */
3637 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3638 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003639 case STAC_DELL_3ST:
3640 /* GPIO2 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003641 spec->gpio_mask = spec->gpio_dir = 0x04;
3642 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003643 spec->dmic_nids = stac927x_dmic_nids;
3644 spec->num_dmics = STAC927X_NUM_DMICS;
3645
Tobin Davis93ed1502006-09-01 21:03:12 +02003646 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003647 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003648 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003649 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003650 break;
3651 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003652 /* GPIO0 High = Enable EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003653 spec->gpio_mask = spec->gpio_dir = 0x1;
3654 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003655 spec->num_dmics = 0;
3656
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003657 spec->init = stac927x_core_init;
3658 spec->mixer = stac927x_mixer;
3659 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003660
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003661 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003662 spec->aloopback_mask = 0x40;
3663 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003664
Matt Porter3cc08dc2006-01-23 15:27:49 +01003665 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003666 if (!err) {
3667 if (spec->board_config < 0) {
3668 printk(KERN_WARNING "hda_codec: No auto-config is "
3669 "available, default to model=ref\n");
3670 spec->board_config = STAC_D965_REF;
3671 goto again;
3672 }
3673 err = -EINVAL;
3674 }
Mattc7d4b2f2005-06-27 14:59:41 +02003675 if (err < 0) {
3676 stac92xx_free(codec);
3677 return err;
3678 }
Matt2f2f4252005-04-13 14:45:30 +02003679
3680 codec->patch_ops = stac92xx_patch_ops;
3681
Takashi Iwai52987652008-01-16 16:09:47 +01003682 /*
3683 * !!FIXME!!
3684 * The STAC927x seem to require fairly long delays for certain
3685 * command sequences. With too short delays (even if the answer
3686 * is set to RIRB properly), it results in the silence output
3687 * on some hardwares like Dell.
3688 *
3689 * The below flag enables the longer delay (see get_response
3690 * in hda_intel.c).
3691 */
3692 codec->bus->needs_damn_long_delay = 1;
3693
Matt2f2f4252005-04-13 14:45:30 +02003694 return 0;
3695}
3696
Matt Porterf3302a52006-07-31 12:49:34 +02003697static int patch_stac9205(struct hda_codec *codec)
3698{
3699 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003700 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003701
3702 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3703 if (spec == NULL)
3704 return -ENOMEM;
3705
3706 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003707 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003708 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003709 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3710 stac9205_models,
3711 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003712 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003713 if (spec->board_config < 0) {
3714 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3715 err = stac92xx_save_bios_config_regs(codec);
3716 if (err < 0) {
3717 stac92xx_free(codec);
3718 return err;
3719 }
3720 spec->pin_configs = spec->bios_pin_configs;
3721 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003722 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3723 stac92xx_set_config_regs(codec);
3724 }
3725
3726 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003727 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003728 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003729 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003730 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003731 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003732 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003733 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003734 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003735
3736 spec->init = stac9205_core_init;
3737 spec->mixer = stac9205_mixer;
3738
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003739 spec->aloopback_mask = 0x40;
3740 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003741 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003742
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003743 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003744 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003745 /* Enable SPDIF in/out */
3746 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3747 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003748
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003749 /* Enable unsol response for GPIO4/Dock HP connection */
3750 snd_hda_codec_write(codec, codec->afg, 0,
3751 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3752 snd_hda_codec_write_cache(codec, codec->afg, 0,
3753 AC_VERB_SET_UNSOLICITED_ENABLE,
3754 (AC_USRSP_EN | STAC_HP_EVENT));
3755
3756 spec->gpio_dir = 0x0b;
3757 spec->gpio_mask = 0x1b;
3758 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003759 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003760 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003761 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003762 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003763 break;
3764 default:
3765 /* GPIO0 High = EAPD */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003766 spec->gpio_mask = spec->gpio_dir = 0x1;
3767 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003768 break;
3769 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003770
Matt Porterf3302a52006-07-31 12:49:34 +02003771 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003772 if (!err) {
3773 if (spec->board_config < 0) {
3774 printk(KERN_WARNING "hda_codec: No auto-config is "
3775 "available, default to model=ref\n");
3776 spec->board_config = STAC_9205_REF;
3777 goto again;
3778 }
3779 err = -EINVAL;
3780 }
Matt Porterf3302a52006-07-31 12:49:34 +02003781 if (err < 0) {
3782 stac92xx_free(codec);
3783 return err;
3784 }
3785
3786 codec->patch_ops = stac92xx_patch_ops;
3787
3788 return 0;
3789}
3790
Matt2f2f4252005-04-13 14:45:30 +02003791/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003792 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003793 */
3794
Guillaume Munch99ccc562006-08-16 19:35:12 +02003795/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003796static hda_nid_t vaio_dacs[] = { 0x2 };
3797#define VAIO_HP_DAC 0x5
3798static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3799static hda_nid_t vaio_mux_nids[] = { 0x15 };
3800
3801static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003802 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003803 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003804 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003805 { "Mic Jack", 0x1 },
3806 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003807 { "PCM", 0x3 },
3808 }
3809};
3810
3811static struct hda_verb vaio_init[] = {
3812 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003813 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003814 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3815 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3816 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3817 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003818 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003819 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3820 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3821 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3822 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3823 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3824 {}
3825};
3826
Guillaume Munch6d859062006-08-22 17:15:47 +02003827static struct hda_verb vaio_ar_init[] = {
3828 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3829 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3830 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3831 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3832/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
3833 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003834 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02003835 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3836 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3837/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
3838 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3839 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3840 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3841 {}
3842};
3843
Takashi Iwaidb064e52006-03-16 16:04:58 +01003844/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003845static struct hda_bind_ctls vaio_bind_master_vol = {
3846 .ops = &snd_hda_bind_vol,
3847 .values = {
3848 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3849 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3850 0
3851 },
3852};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003853
3854/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02003855static struct hda_bind_ctls vaio_bind_master_sw = {
3856 .ops = &snd_hda_bind_sw,
3857 .values = {
3858 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
3859 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
3860 0,
3861 },
3862};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003863
3864static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003865 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3866 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003867 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3868 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3869 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3870 {
3871 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3872 .name = "Capture Source",
3873 .count = 1,
3874 .info = stac92xx_mux_enum_info,
3875 .get = stac92xx_mux_enum_get,
3876 .put = stac92xx_mux_enum_put,
3877 },
3878 {}
3879};
3880
Guillaume Munch6d859062006-08-22 17:15:47 +02003881static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02003882 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
3883 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02003884 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
3885 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
3886 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
3887 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
3888 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
3889 {
3890 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3891 .name = "Capture Source",
3892 .count = 1,
3893 .info = stac92xx_mux_enum_info,
3894 .get = stac92xx_mux_enum_get,
3895 .put = stac92xx_mux_enum_put,
3896 },
3897 {}
3898};
3899
3900static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01003901 .build_controls = stac92xx_build_controls,
3902 .build_pcms = stac92xx_build_pcms,
3903 .init = stac92xx_init,
3904 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003905#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01003906 .resume = stac92xx_resume,
3907#endif
3908};
3909
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003910static int stac9872_vaio_init(struct hda_codec *codec)
3911{
3912 int err;
3913
3914 err = stac92xx_init(codec);
3915 if (err < 0)
3916 return err;
3917 if (codec->patch_ops.unsol_event)
3918 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3919 return 0;
3920}
3921
3922static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
3923{
Jiang Zhe40c1d302007-11-12 13:05:16 +01003924 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003925 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3926 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3927 } else {
3928 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
3929 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
3930 }
3931}
3932
3933static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
3934{
3935 switch (res >> 26) {
3936 case STAC_HP_EVENT:
3937 stac9872_vaio_hp_detect(codec, res);
3938 break;
3939 }
3940}
3941
3942static struct hda_codec_ops stac9872_vaio_patch_ops = {
3943 .build_controls = stac92xx_build_controls,
3944 .build_pcms = stac92xx_build_pcms,
3945 .init = stac9872_vaio_init,
3946 .free = stac92xx_free,
3947 .unsol_event = stac9872_vaio_unsol_event,
3948#ifdef CONFIG_PM
3949 .resume = stac92xx_resume,
3950#endif
3951};
3952
Guillaume Munch6d859062006-08-22 17:15:47 +02003953enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
3954 CXD9872RD_VAIO,
3955 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
3956 STAC9872AK_VAIO,
3957 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
3958 STAC9872K_VAIO,
3959 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003960 CXD9872AKD_VAIO,
3961 STAC_9872_MODELS,
3962};
Takashi Iwaidb064e52006-03-16 16:04:58 +01003963
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003964static const char *stac9872_models[STAC_9872_MODELS] = {
3965 [CXD9872RD_VAIO] = "vaio",
3966 [CXD9872AKD_VAIO] = "vaio-ar",
3967};
3968
3969static struct snd_pci_quirk stac9872_cfg_tbl[] = {
3970 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
3971 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
3972 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01003973 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01003974 {}
3975};
3976
Guillaume Munch6d859062006-08-22 17:15:47 +02003977static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01003978{
3979 struct sigmatel_spec *spec;
3980 int board_config;
3981
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003982 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
3983 stac9872_models,
3984 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01003985 if (board_config < 0)
3986 /* unknown config, let generic-parser do its job... */
3987 return snd_hda_parse_generic_codec(codec);
3988
3989 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3990 if (spec == NULL)
3991 return -ENOMEM;
3992
3993 codec->spec = spec;
3994 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02003995 case CXD9872RD_VAIO:
3996 case STAC9872AK_VAIO:
3997 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01003998 spec->mixer = vaio_mixer;
3999 spec->init = vaio_init;
4000 spec->multiout.max_channels = 2;
4001 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4002 spec->multiout.dac_nids = vaio_dacs;
4003 spec->multiout.hp_nid = VAIO_HP_DAC;
4004 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4005 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004006 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004007 spec->input_mux = &vaio_mux;
4008 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004009 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004010 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004011
4012 case CXD9872AKD_VAIO:
4013 spec->mixer = vaio_ar_mixer;
4014 spec->init = vaio_ar_init;
4015 spec->multiout.max_channels = 2;
4016 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4017 spec->multiout.dac_nids = vaio_dacs;
4018 spec->multiout.hp_nid = VAIO_HP_DAC;
4019 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004020 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004021 spec->adc_nids = vaio_adcs;
4022 spec->input_mux = &vaio_mux;
4023 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004024 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004025 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004026 }
4027
Takashi Iwaidb064e52006-03-16 16:04:58 +01004028 return 0;
4029}
4030
4031
4032/*
Matt2f2f4252005-04-13 14:45:30 +02004033 * patch entries
4034 */
4035struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4036 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4037 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4038 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4039 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4040 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4041 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4042 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004043 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4044 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4045 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4046 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4047 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4048 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004049 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4050 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4051 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4052 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4053 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4054 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4055 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4056 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4057 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4058 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004059 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4060 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4061 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4062 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4063 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4064 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004065 /* The following does not take into account .id=0x83847661 when subsys =
4066 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4067 * currently not fully supported.
4068 */
4069 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4070 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4071 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004072 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4073 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4074 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4075 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4076 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4077 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4078 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4079 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004080 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4081 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004082 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004083 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4084 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4085 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4086 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4087 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4088 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4089 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4090 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4091 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004092 {} /* terminator */
4093};