blob: 7fdafcb0015d8e9030c13c27b9d060c16ff9b39d [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"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010035#include "hda_patch.h"
Matt2f2f4252005-04-13 14:45:30 +020036
Matt4e550962005-07-04 17:51:39 +020037#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010038#define STAC_PWR_EVENT 0x20
39#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020040
Takashi Iwaif5fcc132006-11-24 17:07:44 +010041enum {
42 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010043 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020044 STAC_9200_DELL_D21,
45 STAC_9200_DELL_D22,
46 STAC_9200_DELL_D23,
47 STAC_9200_DELL_M21,
48 STAC_9200_DELL_M22,
49 STAC_9200_DELL_M23,
50 STAC_9200_DELL_M24,
51 STAC_9200_DELL_M25,
52 STAC_9200_DELL_M26,
53 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020054 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010055 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010056 STAC_9200_MODELS
57};
58
59enum {
60 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020061 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020062 STAC_9205_DELL_M43,
63 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010064 STAC_9205_MODELS
65};
66
67enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010068 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010069 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010070 STAC_92HD73XX_MODELS
71};
72
73enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010074 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010075 STAC_DELL_M4_1,
76 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010077 STAC_92HD71BXX_MODELS
78};
79
80enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010081 STAC_925x_REF,
82 STAC_M2_2,
83 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020084 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010085 STAC_925x_MODELS
86};
87
88enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010089 STAC_D945_REF,
90 STAC_D945GTP3,
91 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020092 STAC_INTEL_MAC_V1,
93 STAC_INTEL_MAC_V2,
94 STAC_INTEL_MAC_V3,
95 STAC_INTEL_MAC_V4,
96 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +080097 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
98 * is given, one of the above models will be
99 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200100 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100101 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100102 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100103 STAC_MACBOOK_PRO_V1,
104 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200105 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200106 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200107 STAC_922X_DELL_D81,
108 STAC_922X_DELL_D82,
109 STAC_922X_DELL_M81,
110 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100111 STAC_922X_MODELS
112};
113
114enum {
115 STAC_D965_REF,
116 STAC_D965_3ST,
117 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200118 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100119 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100120 STAC_927X_MODELS
121};
Matt Porter403d1942005-11-29 15:00:51 +0100122
Matt2f2f4252005-04-13 14:45:30 +0200123struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100124 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200125 unsigned int num_mixers;
126
Matt Porter403d1942005-11-29 15:00:51 +0100127 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200128 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100129 unsigned int line_switch: 1;
130 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100131 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100132 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200133
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +0100134 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200135 unsigned int eapd_mask;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +0100136 unsigned int gpio_mask;
137 unsigned int gpio_dir;
138 unsigned int gpio_data;
139 unsigned int gpio_mute;
140
141 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100142 unsigned char aloopback_mask;
143 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200144
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100145 /* power management */
146 unsigned int num_pwrs;
147 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100148 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100149
Matt2f2f4252005-04-13 14:45:30 +0200150 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100151 struct hda_input_mux *mono_mux;
152 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200153 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100154 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200155
156 /* capture */
157 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200158 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200159 hda_nid_t *mux_nids;
160 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200161 hda_nid_t *dmic_nids;
162 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100163 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100164 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200165 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100166 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200167
Matt2f2f4252005-04-13 14:45:30 +0200168 /* pin widgets */
169 hda_nid_t *pin_nids;
170 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200171 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200172 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200173
174 /* codec specific stuff */
175 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100176 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200177
178 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200179 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100180 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200181 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100182 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200183
Matt Porter403d1942005-11-29 15:00:51 +0100184 /* i/o switches */
185 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200186 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200187 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200188 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200189
Mattc7d4b2f2005-06-27 14:59:41 +0200190 struct hda_pcm pcm_rec[2]; /* PCM information */
191
192 /* dynamic controls and input_mux */
193 struct auto_pin_cfg autocfg;
194 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100195 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200196 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200197 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100198 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200199};
200
201static hda_nid_t stac9200_adc_nids[1] = {
202 0x03,
203};
204
205static hda_nid_t stac9200_mux_nids[1] = {
206 0x0c,
207};
208
209static hda_nid_t stac9200_dac_nids[1] = {
210 0x02,
211};
212
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100213static hda_nid_t stac92hd73xx_pwr_nids[8] = {
214 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
215 0x0f, 0x10, 0x11
216};
217
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100218static hda_nid_t stac92hd73xx_adc_nids[2] = {
219 0x1a, 0x1b
220};
221
222#define STAC92HD73XX_NUM_DMICS 2
223static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
224 0x13, 0x14, 0
225};
226
227#define STAC92HD73_DAC_COUNT 5
228static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
229 0x15, 0x16, 0x17, 0x18, 0x19,
230};
231
232static hda_nid_t stac92hd73xx_mux_nids[4] = {
233 0x28, 0x29, 0x2a, 0x2b,
234};
235
236static hda_nid_t stac92hd73xx_dmux_nids[2] = {
237 0x20, 0x21,
238};
239
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100240static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
241 0x0a, 0x0d, 0x0f
242};
243
Matthew Ranostaye035b842007-11-06 11:53:55 +0100244static hda_nid_t stac92hd71bxx_adc_nids[2] = {
245 0x12, 0x13,
246};
247
248static hda_nid_t stac92hd71bxx_mux_nids[2] = {
249 0x1a, 0x1b
250};
251
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100252static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
253 0x1c,
254};
255
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100256static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100257 0x10, /*0x11, */
258};
259
260#define STAC92HD71BXX_NUM_DMICS 2
261static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
262 0x18, 0x19, 0
263};
264
Tobin Davis8e21c342007-01-08 11:04:17 +0100265static hda_nid_t stac925x_adc_nids[1] = {
266 0x03,
267};
268
269static hda_nid_t stac925x_mux_nids[1] = {
270 0x0f,
271};
272
273static hda_nid_t stac925x_dac_nids[1] = {
274 0x02,
275};
276
Takashi Iwaif6e98522007-10-16 14:27:04 +0200277#define STAC925X_NUM_DMICS 1
278static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
279 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200280};
281
Takashi Iwai1697055e2007-12-18 18:05:52 +0100282static hda_nid_t stac925x_dmux_nids[1] = {
283 0x14,
284};
285
Matt2f2f4252005-04-13 14:45:30 +0200286static hda_nid_t stac922x_adc_nids[2] = {
287 0x06, 0x07,
288};
289
290static hda_nid_t stac922x_mux_nids[2] = {
291 0x12, 0x13,
292};
293
Matt Porter3cc08dc2006-01-23 15:27:49 +0100294static hda_nid_t stac927x_adc_nids[3] = {
295 0x07, 0x08, 0x09
296};
297
298static hda_nid_t stac927x_mux_nids[3] = {
299 0x15, 0x16, 0x17
300};
301
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100302static hda_nid_t stac927x_dac_nids[6] = {
303 0x02, 0x03, 0x04, 0x05, 0x06, 0
304};
305
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100306static hda_nid_t stac927x_dmux_nids[1] = {
307 0x1b,
308};
309
Matthew Ranostay7f168592007-10-18 17:38:17 +0200310#define STAC927X_NUM_DMICS 2
311static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
312 0x13, 0x14, 0
313};
314
Matt Porterf3302a52006-07-31 12:49:34 +0200315static hda_nid_t stac9205_adc_nids[2] = {
316 0x12, 0x13
317};
318
319static hda_nid_t stac9205_mux_nids[2] = {
320 0x19, 0x1a
321};
322
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100323static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100324 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100325};
326
Takashi Iwaif6e98522007-10-16 14:27:04 +0200327#define STAC9205_NUM_DMICS 2
328static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
329 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200330};
331
Mattc7d4b2f2005-06-27 14:59:41 +0200332static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200333 0x08, 0x09, 0x0d, 0x0e,
334 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200335};
336
Tobin Davis8e21c342007-01-08 11:04:17 +0100337static hda_nid_t stac925x_pin_nids[8] = {
338 0x07, 0x08, 0x0a, 0x0b,
339 0x0c, 0x0d, 0x10, 0x11,
340};
341
Matt2f2f4252005-04-13 14:45:30 +0200342static hda_nid_t stac922x_pin_nids[10] = {
343 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
344 0x0f, 0x10, 0x11, 0x15, 0x1b,
345};
346
Matthew Ranostaya7662642008-02-21 07:51:14 +0100347static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100348 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
349 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100350 0x14, 0x1e, 0x22
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100351};
352
Matthew Ranostaye035b842007-11-06 11:53:55 +0100353static hda_nid_t stac92hd71bxx_pin_nids[10] = {
354 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
355 0x0f, 0x14, 0x18, 0x19, 0x1e,
356};
357
Matt Porter3cc08dc2006-01-23 15:27:49 +0100358static hda_nid_t stac927x_pin_nids[14] = {
359 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
360 0x0f, 0x10, 0x11, 0x12, 0x13,
361 0x14, 0x21, 0x22, 0x23,
362};
363
Matt Porterf3302a52006-07-31 12:49:34 +0200364static hda_nid_t stac9205_pin_nids[12] = {
365 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
366 0x0f, 0x14, 0x16, 0x17, 0x18,
367 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200368};
369
Matt Porter8b657272006-10-26 17:12:59 +0200370static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
371 struct snd_ctl_elem_info *uinfo)
372{
373 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
374 struct sigmatel_spec *spec = codec->spec;
375 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
376}
377
378static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
379 struct snd_ctl_elem_value *ucontrol)
380{
381 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
382 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100383 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200384
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100385 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200386 return 0;
387}
388
389static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
390 struct snd_ctl_elem_value *ucontrol)
391{
392 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
393 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100394 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200395
396 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100397 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200398}
399
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100400static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200401{
402 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
403 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200404 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200405}
406
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100407static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200408{
409 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
410 struct sigmatel_spec *spec = codec->spec;
411 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
412
413 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
414 return 0;
415}
416
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100417static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200418{
419 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
420 struct sigmatel_spec *spec = codec->spec;
421 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
422
Mattc7d4b2f2005-06-27 14:59:41 +0200423 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200424 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
425}
426
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100427static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
428 struct snd_ctl_elem_info *uinfo)
429{
430 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
431 struct sigmatel_spec *spec = codec->spec;
432 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
433}
434
435static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
436 struct snd_ctl_elem_value *ucontrol)
437{
438 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
439 struct sigmatel_spec *spec = codec->spec;
440
441 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
442 return 0;
443}
444
445static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
446 struct snd_ctl_elem_value *ucontrol)
447{
448 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
449 struct sigmatel_spec *spec = codec->spec;
450
451 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
452 spec->mono_nid, &spec->cur_mmux);
453}
454
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200455#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
456
457static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
458 struct snd_ctl_elem_value *ucontrol)
459{
460 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100461 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200462 struct sigmatel_spec *spec = codec->spec;
463
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100464 ucontrol->value.integer.value[0] = !!(spec->aloopback &
465 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200466 return 0;
467}
468
469static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
470 struct snd_ctl_elem_value *ucontrol)
471{
472 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
473 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100474 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200475 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100476 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200477
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100478 idx_val = spec->aloopback_mask << idx;
479 if (ucontrol->value.integer.value[0])
480 val = spec->aloopback | idx_val;
481 else
482 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100483 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200484 return 0;
485
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100486 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200487
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100488 /* Only return the bits defined by the shift value of the
489 * first two bytes of the mask
490 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200491 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100492 kcontrol->private_value & 0xFFFF, 0x0);
493 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200494
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100495 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200496 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100497 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200498 } else {
499 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100500 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200501 }
502
503 snd_hda_codec_write_cache(codec, codec->afg, 0,
504 kcontrol->private_value >> 16, dac_mode);
505
506 return 1;
507}
508
Mattc7d4b2f2005-06-27 14:59:41 +0200509static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200510 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200511 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200512 {}
513};
514
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200515static struct hda_verb stac9200_eapd_init[] = {
516 /* set dac0mux for dac converter */
517 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
518 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
519 {}
520};
521
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100522static struct hda_verb stac92hd73xx_6ch_core_init[] = {
523 /* set master volume and direct control */
524 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
525 /* setup audio connections */
526 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
527 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
528 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
529 /* setup adcs to point to mixer */
530 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
531 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100532 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
533 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
534 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
535 /* setup import muxs */
536 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
537 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
538 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
539 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
540 {}
541};
542
Matthew Ranostayd654a662008-03-14 08:46:51 +0100543static struct hda_verb dell_eq_core_init[] = {
544 /* set master volume to max value without distortion
545 * and direct control */
546 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
547 /* setup audio connections */
548 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
549 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
550 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
551 /* setup adcs to point to mixer */
552 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
553 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
554 /* setup import muxs */
555 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
556 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
557 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
558 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
559 {}
560};
561
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100562static struct hda_verb dell_m6_core_init[] = {
563 /* set master volume and direct control */
564 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
565 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100566 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
567 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100568 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
569 /* setup adcs to point to mixer */
570 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
571 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
572 /* setup import muxs */
573 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
574 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
575 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
576 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
577 {}
578};
579
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100580static struct hda_verb stac92hd73xx_8ch_core_init[] = {
581 /* set master volume and direct control */
582 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
583 /* setup audio connections */
584 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
585 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
586 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
587 /* connect hp ports to dac3 */
588 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
589 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
590 /* setup adcs to point to mixer */
591 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
592 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100593 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
594 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
595 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
596 /* setup import muxs */
597 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
598 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
599 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
600 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
601 {}
602};
603
604static struct hda_verb stac92hd73xx_10ch_core_init[] = {
605 /* set master volume and direct control */
606 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
607 /* setup audio connections */
608 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
609 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
610 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
611 /* dac3 is connected to import3 mux */
612 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
613 /* connect hp ports to dac4 */
614 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
615 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
616 /* setup adcs to point to mixer */
617 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
618 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100619 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
620 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
621 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
622 /* setup import muxs */
623 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
624 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
625 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
626 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
627 {}
628};
629
Matthew Ranostaye035b842007-11-06 11:53:55 +0100630static struct hda_verb stac92hd71bxx_core_init[] = {
631 /* set master volume and direct control */
632 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
633 /* connect headphone jack to dac1 */
634 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100635 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
636 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
637 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
638 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
639 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100640};
641
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200642#define HD_DISABLE_PORTF 3
Matthew Ranostay541eee82007-12-14 12:08:04 +0100643static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200644 /* start of config #1 */
645
646 /* connect port 0f to audio mixer */
647 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
648 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
649 /* unmute right and left channels for node 0x0f */
650 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
651 /* start of config #2 */
652
Matthew Ranostay541eee82007-12-14 12:08:04 +0100653 /* set master volume and direct control */
654 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
655 /* connect headphone jack to dac1 */
656 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200657 /* connect port 0d to audio mixer */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100658 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100659 /* unmute dac0 input in audio mixer */
660 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200661 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100662 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
663 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100664 {}
665};
666
Tobin Davis8e21c342007-01-08 11:04:17 +0100667static struct hda_verb stac925x_core_init[] = {
668 /* set dac0mux for dac converter */
669 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
670 {}
671};
672
Mattc7d4b2f2005-06-27 14:59:41 +0200673static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200674 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200675 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200676 {}
677};
678
Tobin Davis93ed1502006-09-01 21:03:12 +0200679static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200680 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200681 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200682 /* unmute node 0x1b */
683 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
684 /* select node 0x03 as DAC */
685 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
686 {}
687};
688
Matt Porter3cc08dc2006-01-23 15:27:49 +0100689static struct hda_verb stac927x_core_init[] = {
690 /* set master volume and direct control */
691 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
692 {}
693};
694
Matt Porterf3302a52006-07-31 12:49:34 +0200695static struct hda_verb stac9205_core_init[] = {
696 /* set master volume and direct control */
697 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
698 {}
699};
700
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100701#define STAC_MONO_MUX \
702 { \
703 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
704 .name = "Mono Mux", \
705 .count = 1, \
706 .info = stac92xx_mono_mux_enum_info, \
707 .get = stac92xx_mono_mux_enum_get, \
708 .put = stac92xx_mono_mux_enum_put, \
709 }
710
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200711#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200712 { \
713 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
714 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200715 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200716 .info = stac92xx_mux_enum_info, \
717 .get = stac92xx_mux_enum_get, \
718 .put = stac92xx_mux_enum_put, \
719 }
720
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100721#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200722 { \
723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
724 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100725 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200726 .info = stac92xx_aloopback_info, \
727 .get = stac92xx_aloopback_get, \
728 .put = stac92xx_aloopback_put, \
729 .private_value = verb_read | (verb_write << 16), \
730 }
731
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100732static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200733 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
734 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200735 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200736 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
737 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200738 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200739 { } /* end */
740};
741
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100742static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100743 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
744
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100745 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
746 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
747
748 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
749 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
750
751 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
752 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
753
754 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
755 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
756
757 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
758 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
759
760 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
761 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
762
763 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
764 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
765 { } /* end */
766};
767
768static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100769 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
770
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100771 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
772 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
773
774 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
775 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
776
777 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
778 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
779
780 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
781 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
782
783 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
784 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
785
786 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
787 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
788
789 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
790 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
791 { } /* end */
792};
793
794static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100795 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
796
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100797 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
798 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
799
800 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
801 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
802
803 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
804 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
805
806 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
807 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
808
809 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
810 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
811
812 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
813 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
814
815 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
816 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
817 { } /* end */
818};
819
Matthew Ranostay541eee82007-12-14 12:08:04 +0100820static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100821 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100822
Matthew Ranostay9b359472007-11-07 13:03:12 +0100823 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
824 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
825 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
826
827 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
828 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
829 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
830
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200831 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
832 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
833
Matthew Ranostay9b359472007-11-07 13:03:12 +0100834 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
835 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100836 { } /* end */
837};
838
Matthew Ranostay541eee82007-12-14 12:08:04 +0100839static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100840 STAC_INPUT_SOURCE(2),
841 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
842
Matthew Ranostay541eee82007-12-14 12:08:04 +0100843 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
844 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
845 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
846
847 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
848 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
849 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
850 { } /* end */
851};
852
Tobin Davis8e21c342007-01-08 11:04:17 +0100853static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200854 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100855 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +0200856 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +0100857 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
858 { } /* end */
859};
860
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100861static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200862 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100863 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200864
865 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
866 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
867 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
868
869 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
870 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
871 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
872
873 { } /* end */
874};
875
876/* This needs to be generated dynamically based on sequence */
877static struct snd_kcontrol_new stac922x_mixer[] = {
878 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200879 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
880 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
881 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
882
883 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
884 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
885 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
886 { } /* end */
887};
888
889
890static struct snd_kcontrol_new stac927x_mixer[] = {
891 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100892 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200893
894 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
895 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
896 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
897
898 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
899 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
900 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
901
902 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
903 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
904 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200905 { } /* end */
906};
907
Takashi Iwai1697055e2007-12-18 18:05:52 +0100908static struct snd_kcontrol_new stac_dmux_mixer = {
909 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
910 .name = "Digital Input Source",
911 /* count set later */
912 .info = stac92xx_dmux_enum_info,
913 .get = stac92xx_dmux_enum_get,
914 .put = stac92xx_dmux_enum_put,
915};
916
Takashi Iwai2134ea42008-01-10 16:53:55 +0100917static const char *slave_vols[] = {
918 "Front Playback Volume",
919 "Surround Playback Volume",
920 "Center Playback Volume",
921 "LFE Playback Volume",
922 "Side Playback Volume",
923 "Headphone Playback Volume",
924 "Headphone Playback Volume",
925 "Speaker Playback Volume",
926 "External Speaker Playback Volume",
927 "Speaker2 Playback Volume",
928 NULL
929};
930
931static const char *slave_sws[] = {
932 "Front Playback Switch",
933 "Surround Playback Switch",
934 "Center Playback Switch",
935 "LFE Playback Switch",
936 "Side Playback Switch",
937 "Headphone Playback Switch",
938 "Headphone Playback Switch",
939 "Speaker Playback Switch",
940 "External Speaker Playback Switch",
941 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100942 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100943 NULL
944};
945
Matt2f2f4252005-04-13 14:45:30 +0200946static int stac92xx_build_controls(struct hda_codec *codec)
947{
948 struct sigmatel_spec *spec = codec->spec;
949 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200950 int i;
Matt2f2f4252005-04-13 14:45:30 +0200951
952 err = snd_hda_add_new_ctls(codec, spec->mixer);
953 if (err < 0)
954 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200955
956 for (i = 0; i < spec->num_mixers; i++) {
957 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
958 if (err < 0)
959 return err;
960 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100961 if (spec->num_dmuxes > 0) {
962 stac_dmux_mixer.count = spec->num_dmuxes;
963 err = snd_ctl_add(codec->bus->card,
964 snd_ctl_new1(&stac_dmux_mixer, codec));
965 if (err < 0)
966 return err;
967 }
Mattc7d4b2f2005-06-27 14:59:41 +0200968
Mattdabbed62005-06-14 10:19:34 +0200969 if (spec->multiout.dig_out_nid) {
970 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
971 if (err < 0)
972 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100973 err = snd_hda_create_spdif_share_sw(codec,
974 &spec->multiout);
975 if (err < 0)
976 return err;
977 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200978 }
979 if (spec->dig_in_nid) {
980 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
981 if (err < 0)
982 return err;
983 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100984
985 /* if we have no master control, let's create it */
986 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100987 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100988 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100989 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100990 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100991 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100992 if (err < 0)
993 return err;
994 }
995 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
996 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
997 NULL, slave_sws);
998 if (err < 0)
999 return err;
1000 }
1001
Mattdabbed62005-06-14 10:19:34 +02001002 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001003}
1004
Matt Porter403d1942005-11-29 15:00:51 +01001005static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001006 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001007 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1008};
1009
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001010/*
1011 STAC 9200 pin configs for
1012 102801A8
1013 102801DE
1014 102801E8
1015*/
1016static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001017 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1018 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001019};
1020
1021/*
1022 STAC 9200 pin configs for
1023 102801C0
1024 102801C1
1025*/
1026static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001027 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1028 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001029};
1030
1031/*
1032 STAC 9200 pin configs for
1033 102801C4 (Dell Dimension E310)
1034 102801C5
1035 102801C7
1036 102801D9
1037 102801DA
1038 102801E3
1039*/
1040static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001041 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1042 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001043};
1044
1045
1046/*
1047 STAC 9200-32 pin configs for
1048 102801B5 (Dell Inspiron 630m)
1049 102801D8 (Dell Inspiron 640m)
1050*/
1051static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001052 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1053 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001054};
1055
1056/*
1057 STAC 9200-32 pin configs for
1058 102801C2 (Dell Latitude D620)
1059 102801C8
1060 102801CC (Dell Latitude D820)
1061 102801D4
1062 102801D6
1063*/
1064static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001065 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1066 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001067};
1068
1069/*
1070 STAC 9200-32 pin configs for
1071 102801CE (Dell XPS M1710)
1072 102801CF (Dell Precision M90)
1073*/
1074static unsigned int dell9200_m23_pin_configs[8] = {
1075 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1076 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1077};
1078
1079/*
1080 STAC 9200-32 pin configs for
1081 102801C9
1082 102801CA
1083 102801CB (Dell Latitude 120L)
1084 102801D3
1085*/
1086static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001087 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1088 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001089};
1090
1091/*
1092 STAC 9200-32 pin configs for
1093 102801BD (Dell Inspiron E1505n)
1094 102801EE
1095 102801EF
1096*/
1097static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001098 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1099 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001100};
1101
1102/*
1103 STAC 9200-32 pin configs for
1104 102801F5 (Dell Inspiron 1501)
1105 102801F6
1106*/
1107static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001108 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1109 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001110};
1111
1112/*
1113 STAC 9200-32
1114 102801CD (Dell Inspiron E1705/9400)
1115*/
1116static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001117 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1118 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001119};
1120
Tobin Davisbf277782008-02-03 20:31:47 +01001121static unsigned int oqo9200_pin_configs[8] = {
1122 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1123 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1124};
1125
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001126
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001127static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1128 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001129 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001130 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1131 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1132 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1133 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1134 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1135 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1136 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1137 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1138 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1139 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001140 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001141};
1142
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001143static const char *stac9200_models[STAC_9200_MODELS] = {
1144 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001145 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001146 [STAC_9200_DELL_D21] = "dell-d21",
1147 [STAC_9200_DELL_D22] = "dell-d22",
1148 [STAC_9200_DELL_D23] = "dell-d23",
1149 [STAC_9200_DELL_M21] = "dell-m21",
1150 [STAC_9200_DELL_M22] = "dell-m22",
1151 [STAC_9200_DELL_M23] = "dell-m23",
1152 [STAC_9200_DELL_M24] = "dell-m24",
1153 [STAC_9200_DELL_M25] = "dell-m25",
1154 [STAC_9200_DELL_M26] = "dell-m26",
1155 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001156 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001157 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001158};
1159
1160static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1161 /* SigmaTel reference board */
1162 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1163 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001164 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001165 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1166 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001167 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001168 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1169 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1170 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1171 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1172 "unknown Dell", STAC_9200_DELL_D22),
1173 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1174 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001175 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001176 "Dell Latitude D620", STAC_9200_DELL_M22),
1177 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1178 "unknown Dell", STAC_9200_DELL_D23),
1179 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1180 "unknown Dell", STAC_9200_DELL_D23),
1181 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1182 "unknown Dell", STAC_9200_DELL_M22),
1183 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1184 "unknown Dell", STAC_9200_DELL_M24),
1185 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1186 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001187 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001188 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001189 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001190 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001191 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001192 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001193 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001194 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001195 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001196 "Dell Precision M90", STAC_9200_DELL_M23),
1197 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1198 "unknown Dell", STAC_9200_DELL_M22),
1199 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1200 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001201 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001202 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001203 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001204 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1205 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1206 "unknown Dell", STAC_9200_DELL_D23),
1207 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1208 "unknown Dell", STAC_9200_DELL_D23),
1209 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1210 "unknown Dell", STAC_9200_DELL_D21),
1211 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1212 "unknown Dell", STAC_9200_DELL_D23),
1213 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1214 "unknown Dell", STAC_9200_DELL_D21),
1215 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1216 "unknown Dell", STAC_9200_DELL_M25),
1217 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1218 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001219 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001220 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1221 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1222 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001223 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001224 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001225 /* Gateway machines needs EAPD to be set on resume */
1226 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1227 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1228 STAC_9200_GATEWAY),
1229 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1230 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001231 /* OQO Mobile */
1232 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001233 {} /* terminator */
1234};
1235
Tobin Davis8e21c342007-01-08 11:04:17 +01001236static unsigned int ref925x_pin_configs[8] = {
1237 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001238 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001239};
1240
1241static unsigned int stac925x_MA6_pin_configs[8] = {
1242 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1243 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1244};
1245
Tobin Davis2c11f952007-05-17 09:36:34 +02001246static unsigned int stac925x_PA6_pin_configs[8] = {
1247 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1248 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1249};
1250
Tobin Davis8e21c342007-01-08 11:04:17 +01001251static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001252 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1253 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001254};
1255
1256static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1257 [STAC_REF] = ref925x_pin_configs,
1258 [STAC_M2_2] = stac925xM2_2_pin_configs,
1259 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001260 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001261};
1262
1263static const char *stac925x_models[STAC_925x_MODELS] = {
1264 [STAC_REF] = "ref",
1265 [STAC_M2_2] = "m2-2",
1266 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001267 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001268};
1269
1270static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1271 /* SigmaTel reference board */
1272 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001273 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001274 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1275 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1276 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001277 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001278 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1279 {} /* terminator */
1280};
1281
Matthew Ranostaya7662642008-02-21 07:51:14 +01001282static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001283 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1284 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1285 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001286 0x01452050,
1287};
1288
1289static unsigned int dell_m6_pin_configs[13] = {
1290 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001291 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001292 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1293 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001294};
1295
1296static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001297 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1298 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001299};
1300
1301static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1302 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001303 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001304};
1305
1306static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1307 /* SigmaTel reference board */
1308 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001309 "DFI LanParty", STAC_92HD73XX_REF),
1310 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1311 "unknown Dell", STAC_DELL_M6),
1312 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1313 "unknown Dell", STAC_DELL_M6),
1314 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1315 "unknown Dell", STAC_DELL_M6),
1316 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1317 "unknown Dell", STAC_DELL_M6),
1318 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1319 "unknown Dell", STAC_DELL_M6),
1320 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1321 "unknown Dell", STAC_DELL_M6),
1322 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1323 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001324 {} /* terminator */
1325};
1326
Matthew Ranostaye035b842007-11-06 11:53:55 +01001327static unsigned int ref92hd71bxx_pin_configs[10] = {
1328 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001329 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001330 0x90a000f0, 0x01452050,
1331};
1332
Matthew Ranostayaafc4412008-06-13 18:04:33 +02001333static unsigned int dell_m4_1_pin_configs[10] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001334 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001335 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001336 0x40f000f0, 0x4f0000f0,
1337};
1338
Matthew Ranostayaafc4412008-06-13 18:04:33 +02001339static unsigned int dell_m4_2_pin_configs[10] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001340 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1341 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1342 0x40f000f0, 0x044413b0,
1343};
1344
Matthew Ranostaye035b842007-11-06 11:53:55 +01001345static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1346 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001347 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1348 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001349};
1350
1351static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1352 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001353 [STAC_DELL_M4_1] = "dell-m4-1",
1354 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001355};
1356
1357static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1358 /* SigmaTel reference board */
1359 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1360 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001361 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1362 "unknown Dell", STAC_DELL_M4_1),
1363 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1364 "unknown Dell", STAC_DELL_M4_1),
1365 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1366 "unknown Dell", STAC_DELL_M4_1),
1367 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1368 "unknown Dell", STAC_DELL_M4_1),
1369 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1370 "unknown Dell", STAC_DELL_M4_1),
1371 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1372 "unknown Dell", STAC_DELL_M4_1),
1373 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1374 "unknown Dell", STAC_DELL_M4_1),
1375 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1376 "unknown Dell", STAC_DELL_M4_2),
1377 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1378 "unknown Dell", STAC_DELL_M4_2),
1379 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1380 "unknown Dell", STAC_DELL_M4_2),
1381 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1382 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001383 {} /* terminator */
1384};
1385
Matt Porter403d1942005-11-29 15:00:51 +01001386static unsigned int ref922x_pin_configs[10] = {
1387 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1388 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001389 0x40000100, 0x40000100,
1390};
1391
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001392/*
1393 STAC 922X pin configs for
1394 102801A7
1395 102801AB
1396 102801A9
1397 102801D1
1398 102801D2
1399*/
1400static unsigned int dell_922x_d81_pin_configs[10] = {
1401 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1402 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1403 0x01813122, 0x400001f2,
1404};
1405
1406/*
1407 STAC 922X pin configs for
1408 102801AC
1409 102801D0
1410*/
1411static unsigned int dell_922x_d82_pin_configs[10] = {
1412 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1413 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1414 0x01813122, 0x400001f1,
1415};
1416
1417/*
1418 STAC 922X pin configs for
1419 102801BF
1420*/
1421static unsigned int dell_922x_m81_pin_configs[10] = {
1422 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1423 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1424 0x40C003f1, 0x405003f0,
1425};
1426
1427/*
1428 STAC 9221 A1 pin configs for
1429 102801D7 (Dell XPS M1210)
1430*/
1431static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001432 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1433 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001434 0x508003f3, 0x405003f4,
1435};
1436
Matt Porter403d1942005-11-29 15:00:51 +01001437static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001438 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001439 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1440 0x02a19120, 0x40000100,
1441};
1442
1443static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001444 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1445 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001446 0x02a19320, 0x40000100,
1447};
1448
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001449static unsigned int intel_mac_v1_pin_configs[10] = {
1450 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1451 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001452 0x400000fc, 0x400000fb,
1453};
1454
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001455static unsigned int intel_mac_v2_pin_configs[10] = {
1456 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1457 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001458 0x400000fc, 0x400000fb,
1459};
1460
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001461static unsigned int intel_mac_v3_pin_configs[10] = {
1462 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1463 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1464 0x400000fc, 0x400000fb,
1465};
1466
1467static unsigned int intel_mac_v4_pin_configs[10] = {
1468 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1469 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1470 0x400000fc, 0x400000fb,
1471};
1472
1473static unsigned int intel_mac_v5_pin_configs[10] = {
1474 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1475 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1476 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001477};
1478
Takashi Iwai76c08822007-06-19 12:17:42 +02001479
Takashi Iwai19039bd2006-06-28 15:52:16 +02001480static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001481 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001482 [STAC_D945GTP3] = d945gtp3_pin_configs,
1483 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001484 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1485 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1486 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1487 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1488 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001489 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001490 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001491 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1492 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1493 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1494 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1495 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1496 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001497 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1498 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1499 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1500 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001501};
1502
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001503static const char *stac922x_models[STAC_922X_MODELS] = {
1504 [STAC_D945_REF] = "ref",
1505 [STAC_D945GTP5] = "5stack",
1506 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001507 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1508 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1509 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1510 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1511 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001512 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001513 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001514 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001515 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001516 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1517 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001518 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001519 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001520 [STAC_922X_DELL_D81] = "dell-d81",
1521 [STAC_922X_DELL_D82] = "dell-d82",
1522 [STAC_922X_DELL_M81] = "dell-m81",
1523 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001524};
1525
1526static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1527 /* SigmaTel reference board */
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1529 "DFI LanParty", STAC_D945_REF),
1530 /* Intel 945G based systems */
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1532 "Intel D945G", STAC_D945GTP3),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1534 "Intel D945G", STAC_D945GTP3),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1536 "Intel D945G", STAC_D945GTP3),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1538 "Intel D945G", STAC_D945GTP3),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1540 "Intel D945G", STAC_D945GTP3),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1542 "Intel D945G", STAC_D945GTP3),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1544 "Intel D945G", STAC_D945GTP3),
1545 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1546 "Intel D945G", STAC_D945GTP3),
1547 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1548 "Intel D945G", STAC_D945GTP3),
1549 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1550 "Intel D945G", STAC_D945GTP3),
1551 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1552 "Intel D945G", STAC_D945GTP3),
1553 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1554 "Intel D945G", STAC_D945GTP3),
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1556 "Intel D945G", STAC_D945GTP3),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1558 "Intel D945G", STAC_D945GTP3),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1560 "Intel D945G", STAC_D945GTP3),
1561 /* Intel D945G 5-stack systems */
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1563 "Intel D945G", STAC_D945GTP5),
1564 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1565 "Intel D945G", STAC_D945GTP5),
1566 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1567 "Intel D945G", STAC_D945GTP5),
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1569 "Intel D945G", STAC_D945GTP5),
1570 /* Intel 945P based systems */
1571 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1572 "Intel D945P", STAC_D945GTP3),
1573 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1574 "Intel D945P", STAC_D945GTP3),
1575 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1576 "Intel D945P", STAC_D945GTP3),
1577 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1578 "Intel D945P", STAC_D945GTP3),
1579 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1580 "Intel D945P", STAC_D945GTP3),
1581 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1582 "Intel D945P", STAC_D945GTP5),
1583 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001584 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001585 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001586 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001587 /* Dell systems */
1588 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1589 "unknown Dell", STAC_922X_DELL_D81),
1590 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1591 "unknown Dell", STAC_922X_DELL_D81),
1592 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1593 "unknown Dell", STAC_922X_DELL_D81),
1594 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1595 "unknown Dell", STAC_922X_DELL_D82),
1596 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1597 "unknown Dell", STAC_922X_DELL_M81),
1598 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1599 "unknown Dell", STAC_922X_DELL_D82),
1600 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1601 "unknown Dell", STAC_922X_DELL_D81),
1602 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1603 "unknown Dell", STAC_922X_DELL_D81),
1604 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1605 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001606 {} /* terminator */
1607};
1608
Matt Porter3cc08dc2006-01-23 15:27:49 +01001609static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001610 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1611 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1612 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1613 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001614};
1615
Tobin Davis93ed1502006-09-01 21:03:12 +02001616static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001617 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1618 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1619 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1620 0x40000100, 0x40000100
1621};
1622
Tobin Davis93ed1502006-09-01 21:03:12 +02001623static unsigned int d965_5st_pin_configs[14] = {
1624 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1625 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1626 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1627 0x40000100, 0x40000100
1628};
1629
Tobin Davis4ff076e2007-08-07 11:48:12 +02001630static unsigned int dell_3st_pin_configs[14] = {
1631 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1632 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001633 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001634 0x40c003fc, 0x40000100
1635};
1636
Tobin Davis93ed1502006-09-01 21:03:12 +02001637static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001638 [STAC_D965_REF] = ref927x_pin_configs,
1639 [STAC_D965_3ST] = d965_3st_pin_configs,
1640 [STAC_D965_5ST] = d965_5st_pin_configs,
1641 [STAC_DELL_3ST] = dell_3st_pin_configs,
1642 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001643};
1644
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001645static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001646 [STAC_D965_REF] = "ref",
1647 [STAC_D965_3ST] = "3stack",
1648 [STAC_D965_5ST] = "5stack",
1649 [STAC_DELL_3ST] = "dell-3stack",
1650 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001651};
1652
1653static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1654 /* SigmaTel reference board */
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1656 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001657 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001658 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1659 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001660 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001661 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1662 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1663 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1664 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1665 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1666 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1667 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1668 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1669 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1670 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1671 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1672 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1674 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1675 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1676 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001677 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001678 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001679 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001680 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1681 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001682 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001683 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1684 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001685 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1686 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1687 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1688 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1689 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1690 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001691 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001692 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1693 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1694 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1695 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1696 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1697 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1698 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1699 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1700 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001701 {} /* terminator */
1702};
1703
Matt Porterf3302a52006-07-31 12:49:34 +02001704static unsigned int ref9205_pin_configs[12] = {
1705 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001706 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001707 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001708};
1709
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001710/*
1711 STAC 9205 pin configs for
1712 102801F1
1713 102801F2
1714 102801FC
1715 102801FD
1716 10280204
1717 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001718 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001719*/
1720static unsigned int dell_9205_m42_pin_configs[12] = {
1721 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1722 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1723 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1724};
1725
1726/*
1727 STAC 9205 pin configs for
1728 102801F9
1729 102801FA
1730 102801FE
1731 102801FF (Dell Precision M4300)
1732 10280206
1733 10280200
1734 10280201
1735*/
1736static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001737 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1738 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1739 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1740};
1741
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001742static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001743 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1744 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1745 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1746};
1747
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001748static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001749 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001750 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1751 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1752 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001753};
1754
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001755static const char *stac9205_models[STAC_9205_MODELS] = {
1756 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001757 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001758 [STAC_9205_DELL_M43] = "dell-m43",
1759 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001760};
1761
1762static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1763 /* SigmaTel reference board */
1764 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1765 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001766 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1767 "unknown Dell", STAC_9205_DELL_M42),
1768 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1769 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001770 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001771 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001772 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1773 "Dell Precision", STAC_9205_DELL_M43),
1774 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1775 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001776 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1777 "unknown Dell", STAC_9205_DELL_M42),
1778 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1779 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001780 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1781 "Dell Precision", STAC_9205_DELL_M43),
1782 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001783 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001784 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1785 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02001786 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1787 "Dell Precision", STAC_9205_DELL_M43),
1788 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1789 "Dell Precision", STAC_9205_DELL_M43),
1790 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1791 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001792 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1793 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001794 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1795 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001796 {} /* terminator */
1797};
1798
Richard Fish11b44bb2006-08-23 18:31:34 +02001799static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1800{
1801 int i;
1802 struct sigmatel_spec *spec = codec->spec;
1803
1804 if (! spec->bios_pin_configs) {
1805 spec->bios_pin_configs = kcalloc(spec->num_pins,
1806 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1807 if (! spec->bios_pin_configs)
1808 return -ENOMEM;
1809 }
1810
1811 for (i = 0; i < spec->num_pins; i++) {
1812 hda_nid_t nid = spec->pin_nids[i];
1813 unsigned int pin_cfg;
1814
1815 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1816 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1817 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1818 nid, pin_cfg);
1819 spec->bios_pin_configs[i] = pin_cfg;
1820 }
1821
1822 return 0;
1823}
1824
Matthew Ranostay87d48362007-07-17 11:52:24 +02001825static void stac92xx_set_config_reg(struct hda_codec *codec,
1826 hda_nid_t pin_nid, unsigned int pin_config)
1827{
1828 int i;
1829 snd_hda_codec_write(codec, pin_nid, 0,
1830 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1831 pin_config & 0x000000ff);
1832 snd_hda_codec_write(codec, pin_nid, 0,
1833 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1834 (pin_config & 0x0000ff00) >> 8);
1835 snd_hda_codec_write(codec, pin_nid, 0,
1836 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1837 (pin_config & 0x00ff0000) >> 16);
1838 snd_hda_codec_write(codec, pin_nid, 0,
1839 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1840 pin_config >> 24);
1841 i = snd_hda_codec_read(codec, pin_nid, 0,
1842 AC_VERB_GET_CONFIG_DEFAULT,
1843 0x00);
1844 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1845 pin_nid, i);
1846}
1847
Matt2f2f4252005-04-13 14:45:30 +02001848static void stac92xx_set_config_regs(struct hda_codec *codec)
1849{
1850 int i;
1851 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001852
Matthew Ranostay87d48362007-07-17 11:52:24 +02001853 if (!spec->pin_configs)
1854 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001855
Matthew Ranostay87d48362007-07-17 11:52:24 +02001856 for (i = 0; i < spec->num_pins; i++)
1857 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1858 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001859}
Matt2f2f4252005-04-13 14:45:30 +02001860
Matt2f2f4252005-04-13 14:45:30 +02001861/*
1862 * Analog playback callbacks
1863 */
1864static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1865 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001866 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001867{
1868 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001869 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1870 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001871}
1872
1873static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1874 struct hda_codec *codec,
1875 unsigned int stream_tag,
1876 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001877 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001878{
1879 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001880 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001881}
1882
1883static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1884 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001885 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001886{
1887 struct sigmatel_spec *spec = codec->spec;
1888 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1889}
1890
1891/*
Mattdabbed62005-06-14 10:19:34 +02001892 * Digital playback callbacks
1893 */
1894static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1895 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001896 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001897{
1898 struct sigmatel_spec *spec = codec->spec;
1899 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1900}
1901
1902static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1903 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001904 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001905{
1906 struct sigmatel_spec *spec = codec->spec;
1907 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1908}
1909
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001910static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1911 struct hda_codec *codec,
1912 unsigned int stream_tag,
1913 unsigned int format,
1914 struct snd_pcm_substream *substream)
1915{
1916 struct sigmatel_spec *spec = codec->spec;
1917 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1918 stream_tag, format, substream);
1919}
1920
Mattdabbed62005-06-14 10:19:34 +02001921
1922/*
Matt2f2f4252005-04-13 14:45:30 +02001923 * Analog capture callbacks
1924 */
1925static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1926 struct hda_codec *codec,
1927 unsigned int stream_tag,
1928 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001929 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001930{
1931 struct sigmatel_spec *spec = codec->spec;
1932
1933 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1934 stream_tag, 0, format);
1935 return 0;
1936}
1937
1938static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1939 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001940 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001941{
1942 struct sigmatel_spec *spec = codec->spec;
1943
Takashi Iwai888afa12008-03-18 09:57:50 +01001944 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Matt2f2f4252005-04-13 14:45:30 +02001945 return 0;
1946}
1947
Mattdabbed62005-06-14 10:19:34 +02001948static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1949 .substreams = 1,
1950 .channels_min = 2,
1951 .channels_max = 2,
1952 /* NID is set in stac92xx_build_pcms */
1953 .ops = {
1954 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001955 .close = stac92xx_dig_playback_pcm_close,
1956 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001957 },
1958};
1959
1960static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1961 .substreams = 1,
1962 .channels_min = 2,
1963 .channels_max = 2,
1964 /* NID is set in stac92xx_build_pcms */
1965};
1966
Matt2f2f4252005-04-13 14:45:30 +02001967static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1968 .substreams = 1,
1969 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001970 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001971 .nid = 0x02, /* NID to query formats and rates */
1972 .ops = {
1973 .open = stac92xx_playback_pcm_open,
1974 .prepare = stac92xx_playback_pcm_prepare,
1975 .cleanup = stac92xx_playback_pcm_cleanup
1976 },
1977};
1978
Matt Porter3cc08dc2006-01-23 15:27:49 +01001979static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1980 .substreams = 1,
1981 .channels_min = 2,
1982 .channels_max = 2,
1983 .nid = 0x06, /* NID to query formats and rates */
1984 .ops = {
1985 .open = stac92xx_playback_pcm_open,
1986 .prepare = stac92xx_playback_pcm_prepare,
1987 .cleanup = stac92xx_playback_pcm_cleanup
1988 },
1989};
1990
Matt2f2f4252005-04-13 14:45:30 +02001991static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001992 .channels_min = 2,
1993 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001994 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001995 .ops = {
1996 .prepare = stac92xx_capture_pcm_prepare,
1997 .cleanup = stac92xx_capture_pcm_cleanup
1998 },
1999};
2000
2001static int stac92xx_build_pcms(struct hda_codec *codec)
2002{
2003 struct sigmatel_spec *spec = codec->spec;
2004 struct hda_pcm *info = spec->pcm_rec;
2005
2006 codec->num_pcms = 1;
2007 codec->pcm_info = info;
2008
Mattc7d4b2f2005-06-27 14:59:41 +02002009 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002010 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002011 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002012 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002013 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002014
2015 if (spec->alt_switch) {
2016 codec->num_pcms++;
2017 info++;
2018 info->name = "STAC92xx Analog Alt";
2019 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2020 }
Matt2f2f4252005-04-13 14:45:30 +02002021
Mattdabbed62005-06-14 10:19:34 +02002022 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2023 codec->num_pcms++;
2024 info++;
2025 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002026 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002027 if (spec->multiout.dig_out_nid) {
2028 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2029 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2030 }
2031 if (spec->dig_in_nid) {
2032 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2033 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2034 }
2035 }
2036
Matt2f2f4252005-04-13 14:45:30 +02002037 return 0;
2038}
2039
Takashi Iwaic960a032006-03-23 17:06:28 +01002040static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2041{
2042 unsigned int pincap = snd_hda_param_read(codec, nid,
2043 AC_PAR_PIN_CAP);
2044 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2045 if (pincap & AC_PINCAP_VREF_100)
2046 return AC_PINCTL_VREF_100;
2047 if (pincap & AC_PINCAP_VREF_80)
2048 return AC_PINCTL_VREF_80;
2049 if (pincap & AC_PINCAP_VREF_50)
2050 return AC_PINCTL_VREF_50;
2051 if (pincap & AC_PINCAP_VREF_GRD)
2052 return AC_PINCTL_VREF_GRD;
2053 return 0;
2054}
2055
Matt Porter403d1942005-11-29 15:00:51 +01002056static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2057
2058{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002059 snd_hda_codec_write_cache(codec, nid, 0,
2060 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002061}
2062
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002063#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2064
2065static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2066 struct snd_ctl_elem_value *ucontrol)
2067{
2068 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2069 struct sigmatel_spec *spec = codec->spec;
2070
2071 ucontrol->value.integer.value[0] = spec->hp_switch;
2072 return 0;
2073}
2074
2075static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2076 struct snd_ctl_elem_value *ucontrol)
2077{
2078 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2079 struct sigmatel_spec *spec = codec->spec;
2080
2081 spec->hp_switch = ucontrol->value.integer.value[0];
2082
2083 /* check to be sure that the ports are upto date with
2084 * switch changes
2085 */
2086 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2087
2088 return 1;
2089}
2090
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002091#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002092
2093static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2094{
2095 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2096 struct sigmatel_spec *spec = codec->spec;
2097 int io_idx = kcontrol-> private_value & 0xff;
2098
2099 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2100 return 0;
2101}
2102
2103static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2104{
2105 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2106 struct sigmatel_spec *spec = codec->spec;
2107 hda_nid_t nid = kcontrol->private_value >> 8;
2108 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002109 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002110
2111 spec->io_switch[io_idx] = val;
2112
2113 if (val)
2114 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002115 else {
2116 unsigned int pinctl = AC_PINCTL_IN_EN;
2117 if (io_idx) /* set VREF for mic */
2118 pinctl |= stac92xx_get_vref(codec, nid);
2119 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2120 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002121
2122 /* check the auto-mute again: we need to mute/unmute the speaker
2123 * appropriately according to the pin direction
2124 */
2125 if (spec->hp_detect)
2126 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2127
Matt Porter403d1942005-11-29 15:00:51 +01002128 return 1;
2129}
2130
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002131#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2132
2133static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2134 struct snd_ctl_elem_value *ucontrol)
2135{
2136 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2137 struct sigmatel_spec *spec = codec->spec;
2138
2139 ucontrol->value.integer.value[0] = spec->clfe_swap;
2140 return 0;
2141}
2142
2143static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2144 struct snd_ctl_elem_value *ucontrol)
2145{
2146 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2147 struct sigmatel_spec *spec = codec->spec;
2148 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002149 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002150
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002151 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002152 return 0;
2153
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002154 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002155
2156 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2157 spec->clfe_swap ? 0x4 : 0x0);
2158
2159 return 1;
2160}
2161
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002162#define STAC_CODEC_HP_SWITCH(xname) \
2163 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2164 .name = xname, \
2165 .index = 0, \
2166 .info = stac92xx_hp_switch_info, \
2167 .get = stac92xx_hp_switch_get, \
2168 .put = stac92xx_hp_switch_put, \
2169 }
2170
Matt Porter403d1942005-11-29 15:00:51 +01002171#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2172 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2173 .name = xname, \
2174 .index = 0, \
2175 .info = stac92xx_io_switch_info, \
2176 .get = stac92xx_io_switch_get, \
2177 .put = stac92xx_io_switch_put, \
2178 .private_value = xpval, \
2179 }
2180
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002181#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2182 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2183 .name = xname, \
2184 .index = 0, \
2185 .info = stac92xx_clfe_switch_info, \
2186 .get = stac92xx_clfe_switch_get, \
2187 .put = stac92xx_clfe_switch_put, \
2188 .private_value = xpval, \
2189 }
Matt Porter403d1942005-11-29 15:00:51 +01002190
Mattc7d4b2f2005-06-27 14:59:41 +02002191enum {
2192 STAC_CTL_WIDGET_VOL,
2193 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002194 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002195 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002196 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002197 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002198};
2199
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002200static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002201 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2202 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002203 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002204 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002205 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002206 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002207};
2208
2209/* add dynamic controls */
2210static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2211{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002212 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002213
2214 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2215 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2216
2217 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2218 if (! knew)
2219 return -ENOMEM;
2220 if (spec->kctl_alloc) {
2221 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2222 kfree(spec->kctl_alloc);
2223 }
2224 spec->kctl_alloc = knew;
2225 spec->num_kctl_alloc = num;
2226 }
2227
2228 knew = &spec->kctl_alloc[spec->num_kctl_used];
2229 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002230 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002231 if (! knew->name)
2232 return -ENOMEM;
2233 knew->private_value = val;
2234 spec->num_kctl_used++;
2235 return 0;
2236}
2237
Matt Porter403d1942005-11-29 15:00:51 +01002238/* flag inputs as additional dynamic lineouts */
2239static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2240{
2241 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002242 unsigned int wcaps, wtype;
2243 int i, num_dacs = 0;
2244
2245 /* use the wcaps cache to count all DACs available for line-outs */
2246 for (i = 0; i < codec->num_nodes; i++) {
2247 wcaps = codec->wcaps[i];
2248 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002249
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002250 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2251 num_dacs++;
2252 }
Matt Porter403d1942005-11-29 15:00:51 +01002253
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002254 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2255
Matt Porter403d1942005-11-29 15:00:51 +01002256 switch (cfg->line_outs) {
2257 case 3:
2258 /* add line-in as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002259 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002260 cfg->line_out_pins[cfg->line_outs] =
2261 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002262 spec->line_switch = 1;
2263 cfg->line_outs++;
2264 }
2265 break;
2266 case 2:
2267 /* add line-in as clfe and mic as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002268 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002269 cfg->line_out_pins[cfg->line_outs] =
2270 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002271 spec->line_switch = 1;
2272 cfg->line_outs++;
2273 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002274 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002275 cfg->line_out_pins[cfg->line_outs] =
2276 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002277 spec->mic_switch = 1;
2278 cfg->line_outs++;
2279 }
2280 break;
2281 case 1:
2282 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002283 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002284 cfg->line_out_pins[cfg->line_outs] =
2285 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002286 spec->line_switch = 1;
2287 cfg->line_outs++;
2288 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002289 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002290 cfg->line_out_pins[cfg->line_outs] =
2291 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002292 spec->mic_switch = 1;
2293 cfg->line_outs++;
2294 }
2295 break;
2296 }
2297
2298 return 0;
2299}
2300
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002301
2302static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2303{
2304 int i;
2305
2306 for (i = 0; i < spec->multiout.num_dacs; i++) {
2307 if (spec->multiout.dac_nids[i] == nid)
2308 return 1;
2309 }
2310
2311 return 0;
2312}
2313
Matt Porter3cc08dc2006-01-23 15:27:49 +01002314/*
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002315 * Fill in the dac_nids table from the parsed pin configuration
2316 * This function only works when every pin in line_out_pins[]
2317 * contains atleast one DAC in its connection list. Some 92xx
2318 * codecs are not connected directly to a DAC, such as the 9200
2319 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002320 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002321static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002322 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002323{
2324 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002325 int i, j, conn_len = 0;
2326 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2327 unsigned int wcaps, wtype;
2328
Mattc7d4b2f2005-06-27 14:59:41 +02002329 for (i = 0; i < cfg->line_outs; i++) {
2330 nid = cfg->line_out_pins[i];
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002331 conn_len = snd_hda_get_connections(codec, nid, conn,
2332 HDA_MAX_CONNECTIONS);
2333 for (j = 0; j < conn_len; j++) {
2334 wcaps = snd_hda_param_read(codec, conn[j],
2335 AC_PAR_AUDIO_WIDGET_CAP);
2336 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002337 if (wtype != AC_WID_AUD_OUT ||
2338 (wcaps & AC_WCAP_DIGITAL))
2339 continue;
2340 /* conn[j] is a DAC routed to this line-out */
2341 if (!is_in_dac_nids(spec, conn[j]))
2342 break;
2343 }
2344
2345 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002346 if (spec->multiout.num_dacs > 0) {
2347 /* we have already working output pins,
2348 * so let's drop the broken ones again
2349 */
2350 cfg->line_outs = spec->multiout.num_dacs;
2351 break;
2352 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002353 /* error out, no available DAC found */
2354 snd_printk(KERN_ERR
2355 "%s: No available DAC for pin 0x%x\n",
2356 __func__, nid);
2357 return -ENODEV;
2358 }
2359
2360 spec->multiout.dac_nids[i] = conn[j];
2361 spec->multiout.num_dacs++;
2362 if (conn_len > 1) {
2363 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002364 snd_hda_codec_write_cache(codec, nid, 0,
2365 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002366
2367 }
Mattc7d4b2f2005-06-27 14:59:41 +02002368 }
2369
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002370 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2371 spec->multiout.num_dacs,
2372 spec->multiout.dac_nids[0],
2373 spec->multiout.dac_nids[1],
2374 spec->multiout.dac_nids[2],
2375 spec->multiout.dac_nids[3],
2376 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002377 return 0;
2378}
2379
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002380/* create volume control/switch for the given prefx type */
2381static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2382{
2383 char name[32];
2384 int err;
2385
2386 sprintf(name, "%s Playback Volume", pfx);
2387 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2388 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2389 if (err < 0)
2390 return err;
2391 sprintf(name, "%s Playback Switch", pfx);
2392 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2393 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2394 if (err < 0)
2395 return err;
2396 return 0;
2397}
2398
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002399static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2400{
2401 if (!spec->multiout.hp_nid)
2402 spec->multiout.hp_nid = nid;
2403 else if (spec->multiout.num_dacs > 4) {
2404 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2405 return 1;
2406 } else {
2407 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2408 spec->multiout.num_dacs++;
2409 }
2410 return 0;
2411}
2412
2413static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2414{
2415 if (is_in_dac_nids(spec, nid))
2416 return 1;
2417 if (spec->multiout.hp_nid == nid)
2418 return 1;
2419 return 0;
2420}
2421
Mattc7d4b2f2005-06-27 14:59:41 +02002422/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002423static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002424 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002425{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002426 static const char *chname[4] = {
2427 "Front", "Surround", NULL /*CLFE*/, "Side"
2428 };
Mattc7d4b2f2005-06-27 14:59:41 +02002429 hda_nid_t nid;
2430 int i, err;
2431
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002432 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002433 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002434
2435
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002436 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002437 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002438 continue;
2439
2440 nid = spec->multiout.dac_nids[i];
2441
2442 if (i == 2) {
2443 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002444 err = create_controls(spec, "Center", nid, 1);
2445 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002446 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002447 err = create_controls(spec, "LFE", nid, 2);
2448 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002449 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002450
2451 wid_caps = get_wcaps(codec, nid);
2452
2453 if (wid_caps & AC_WCAP_LR_SWAP) {
2454 err = stac92xx_add_control(spec,
2455 STAC_CTL_WIDGET_CLFE_SWITCH,
2456 "Swap Center/LFE Playback Switch", nid);
2457
2458 if (err < 0)
2459 return err;
2460 }
2461
Mattc7d4b2f2005-06-27 14:59:41 +02002462 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002463 err = create_controls(spec, chname[i], nid, 3);
2464 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002465 return err;
2466 }
2467 }
2468
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002469 if (cfg->hp_outs > 1) {
2470 err = stac92xx_add_control(spec,
2471 STAC_CTL_WIDGET_HP_SWITCH,
2472 "Headphone as Line Out Switch", 0);
2473 if (err < 0)
2474 return err;
2475 }
2476
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002477 if (spec->line_switch) {
2478 nid = cfg->input_pins[AUTO_PIN_LINE];
2479 pincap = snd_hda_param_read(codec, nid,
2480 AC_PAR_PIN_CAP);
2481 if (pincap & AC_PINCAP_OUT) {
2482 err = stac92xx_add_control(spec,
2483 STAC_CTL_WIDGET_IO_SWITCH,
2484 "Line In as Output Switch", nid << 8);
2485 if (err < 0)
2486 return err;
2487 }
2488 }
Matt Porter403d1942005-11-29 15:00:51 +01002489
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002490 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002491 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002492 unsigned int mic_pin = AUTO_PIN_MIC;
2493again:
2494 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002495 def_conf = snd_hda_codec_read(codec, nid, 0,
2496 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002497 /* some laptops have an internal analog microphone
2498 * which can't be used as a output */
2499 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2500 pincap = snd_hda_param_read(codec, nid,
2501 AC_PAR_PIN_CAP);
2502 if (pincap & AC_PINCAP_OUT) {
2503 err = stac92xx_add_control(spec,
2504 STAC_CTL_WIDGET_IO_SWITCH,
2505 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002506 nid = snd_hda_codec_read(codec, nid, 0,
2507 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2508 if (!check_in_dac_nids(spec, nid))
2509 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002510 if (err < 0)
2511 return err;
2512 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002513 } else if (mic_pin == AUTO_PIN_MIC) {
2514 mic_pin = AUTO_PIN_FRONT_MIC;
2515 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002516 }
2517 }
Matt Porter403d1942005-11-29 15:00:51 +01002518
Mattc7d4b2f2005-06-27 14:59:41 +02002519 return 0;
2520}
2521
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002522/* add playback controls for Speaker and HP outputs */
2523static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2524 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002525{
2526 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002527 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002528 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002529
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002530 old_num_dacs = spec->multiout.num_dacs;
2531 for (i = 0; i < cfg->hp_outs; i++) {
2532 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2533 if (wid_caps & AC_WCAP_UNSOL_CAP)
2534 spec->hp_detect = 1;
2535 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2536 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2537 if (check_in_dac_nids(spec, nid))
2538 nid = 0;
2539 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002540 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002541 add_spec_dacs(spec, nid);
2542 }
2543 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002544 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002545 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2546 if (check_in_dac_nids(spec, nid))
2547 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002548 if (! nid)
2549 continue;
2550 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002551 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002552 for (i = 0; i < cfg->line_outs; i++) {
2553 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2554 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2555 if (check_in_dac_nids(spec, nid))
2556 nid = 0;
2557 if (! nid)
2558 continue;
2559 add_spec_dacs(spec, nid);
2560 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002561 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2562 static const char *pfxs[] = {
2563 "Speaker", "External Speaker", "Speaker2",
2564 };
2565 err = create_controls(spec, pfxs[i - old_num_dacs],
2566 spec->multiout.dac_nids[i], 3);
2567 if (err < 0)
2568 return err;
2569 }
2570 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002571 err = create_controls(spec, "Headphone",
2572 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002573 if (err < 0)
2574 return err;
2575 }
Mattc7d4b2f2005-06-27 14:59:41 +02002576
2577 return 0;
2578}
2579
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002580/* labels for mono mux outputs */
2581static const char *stac92xx_mono_labels[3] = {
2582 "DAC0", "DAC1", "Mixer"
2583};
2584
2585/* create mono mux for mono out on capable codecs */
2586static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2587{
2588 struct sigmatel_spec *spec = codec->spec;
2589 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2590 int i, num_cons;
2591 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2592
2593 num_cons = snd_hda_get_connections(codec,
2594 spec->mono_nid,
2595 con_lst,
2596 HDA_MAX_NUM_INPUTS);
2597 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2598 return -EINVAL;
2599
2600 for (i = 0; i < num_cons; i++) {
2601 mono_mux->items[mono_mux->num_items].label =
2602 stac92xx_mono_labels[i];
2603 mono_mux->items[mono_mux->num_items].index = i;
2604 mono_mux->num_items++;
2605 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002606
2607 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2608 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002609}
2610
Matt Porter8b657272006-10-26 17:12:59 +02002611/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002612static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002613 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2614 "Digital Mic 3", "Digital Mic 4"
2615};
2616
2617/* create playback/capture controls for input pins on dmic capable codecs */
2618static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2619 const struct auto_pin_cfg *cfg)
2620{
2621 struct sigmatel_spec *spec = codec->spec;
2622 struct hda_input_mux *dimux = &spec->private_dimux;
2623 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002624 int err, i, j;
2625 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002626
2627 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2628 dimux->items[dimux->num_items].index = 0;
2629 dimux->num_items++;
2630
2631 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002632 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002633 int index;
2634 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002635 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002636 unsigned int def_conf;
2637
2638 def_conf = snd_hda_codec_read(codec,
2639 spec->dmic_nids[i],
2640 0,
2641 AC_VERB_GET_CONFIG_DEFAULT,
2642 0);
2643 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2644 continue;
2645
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002646 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002647 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002648 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002649 con_lst,
2650 HDA_MAX_NUM_INPUTS);
2651 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002652 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002653 index = j;
2654 goto found;
2655 }
2656 continue;
2657found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002658 wcaps = get_wcaps(codec, nid);
2659
2660 if (wcaps & AC_WCAP_OUT_AMP) {
2661 sprintf(name, "%s Capture Volume",
2662 stac92xx_dmic_labels[dimux->num_items]);
2663
2664 err = stac92xx_add_control(spec,
2665 STAC_CTL_WIDGET_VOL,
2666 name,
2667 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2668 if (err < 0)
2669 return err;
2670 }
2671
Matt Porter8b657272006-10-26 17:12:59 +02002672 dimux->items[dimux->num_items].label =
2673 stac92xx_dmic_labels[dimux->num_items];
2674 dimux->items[dimux->num_items].index = index;
2675 dimux->num_items++;
2676 }
2677
2678 return 0;
2679}
2680
Mattc7d4b2f2005-06-27 14:59:41 +02002681/* create playback/capture controls for input pins */
2682static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2683{
2684 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002685 struct hda_input_mux *imux = &spec->private_imux;
2686 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2687 int i, j, k;
2688
2689 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002690 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002691
Takashi Iwai314634b2006-09-21 11:56:18 +02002692 if (!cfg->input_pins[i])
2693 continue;
2694 index = -1;
2695 for (j = 0; j < spec->num_muxes; j++) {
2696 int num_cons;
2697 num_cons = snd_hda_get_connections(codec,
2698 spec->mux_nids[j],
2699 con_lst,
2700 HDA_MAX_NUM_INPUTS);
2701 for (k = 0; k < num_cons; k++)
2702 if (con_lst[k] == cfg->input_pins[i]) {
2703 index = k;
2704 goto found;
2705 }
Mattc7d4b2f2005-06-27 14:59:41 +02002706 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002707 continue;
2708 found:
2709 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2710 imux->items[imux->num_items].index = index;
2711 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002712 }
2713
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002714 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002715 /*
2716 * Set the current input for the muxes.
2717 * The STAC9221 has two input muxes with identical source
2718 * NID lists. Hopefully this won't get confused.
2719 */
2720 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002721 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2722 AC_VERB_SET_CONNECT_SEL,
2723 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002724 }
2725 }
2726
Mattc7d4b2f2005-06-27 14:59:41 +02002727 return 0;
2728}
2729
Mattc7d4b2f2005-06-27 14:59:41 +02002730static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2731{
2732 struct sigmatel_spec *spec = codec->spec;
2733 int i;
2734
2735 for (i = 0; i < spec->autocfg.line_outs; i++) {
2736 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2737 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2738 }
2739}
2740
2741static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2742{
2743 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002744 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002745
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002746 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2747 hda_nid_t pin;
2748 pin = spec->autocfg.hp_pins[i];
2749 if (pin) /* connect to front */
2750 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2751 }
2752 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2753 hda_nid_t pin;
2754 pin = spec->autocfg.speaker_pins[i];
2755 if (pin) /* connect to front */
2756 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2757 }
Mattc7d4b2f2005-06-27 14:59:41 +02002758}
2759
Matt Porter3cc08dc2006-01-23 15:27:49 +01002760static 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 +02002761{
2762 struct sigmatel_spec *spec = codec->spec;
2763 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002764 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002765
Matt Porter8b657272006-10-26 17:12:59 +02002766 if ((err = snd_hda_parse_pin_def_config(codec,
2767 &spec->autocfg,
2768 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002769 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002770 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002771 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002772
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002773 /* If we have no real line-out pin and multiple hp-outs, HPs should
2774 * be set up as multi-channel outputs.
2775 */
2776 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2777 spec->autocfg.hp_outs > 1) {
2778 /* Copy hp_outs to line_outs, backup line_outs in
2779 * speaker_outs so that the following routines can handle
2780 * HP pins as primary outputs.
2781 */
2782 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2783 sizeof(spec->autocfg.line_out_pins));
2784 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2785 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2786 sizeof(spec->autocfg.hp_pins));
2787 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2788 hp_speaker_swap = 1;
2789 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002790 if (spec->autocfg.mono_out_pin) {
2791 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2792 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2793 u32 caps = query_amp_caps(codec,
2794 spec->autocfg.mono_out_pin, dir);
2795 hda_nid_t conn_list[1];
2796
2797 /* get the mixer node and then the mono mux if it exists */
2798 if (snd_hda_get_connections(codec,
2799 spec->autocfg.mono_out_pin, conn_list, 1) &&
2800 snd_hda_get_connections(codec, conn_list[0],
2801 conn_list, 1)) {
2802
2803 int wcaps = get_wcaps(codec, conn_list[0]);
2804 int wid_type = (wcaps & AC_WCAP_TYPE)
2805 >> AC_WCAP_TYPE_SHIFT;
2806 /* LR swap check, some stac925x have a mux that
2807 * changes the DACs output path instead of the
2808 * mono-mux path.
2809 */
2810 if (wid_type == AC_WID_AUD_SEL &&
2811 !(wcaps & AC_WCAP_LR_SWAP))
2812 spec->mono_nid = conn_list[0];
2813 }
2814 /* all mono outs have a least a mute/unmute switch */
2815 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2816 "Mono Playback Switch",
2817 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2818 1, 0, dir));
2819 if (err < 0)
2820 return err;
2821 /* check to see if there is volume support for the amp */
2822 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2823 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2824 "Mono Playback Volume",
2825 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2826 1, 0, dir));
2827 if (err < 0)
2828 return err;
2829 }
2830
2831 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2832 AC_PINCTL_OUT_EN);
2833 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002834
Matt Porter403d1942005-11-29 15:00:51 +01002835 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2836 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002837 if (spec->multiout.num_dacs == 0)
2838 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2839 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002840
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002841 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2842
2843 if (err < 0)
2844 return err;
2845
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002846 if (hp_speaker_swap == 1) {
2847 /* Restore the hp_outs and line_outs */
2848 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2849 sizeof(spec->autocfg.line_out_pins));
2850 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2851 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2852 sizeof(spec->autocfg.speaker_pins));
2853 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2854 memset(spec->autocfg.speaker_pins, 0,
2855 sizeof(spec->autocfg.speaker_pins));
2856 spec->autocfg.speaker_outs = 0;
2857 }
2858
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002859 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2860
2861 if (err < 0)
2862 return err;
2863
2864 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2865
2866 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002867 return err;
2868
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002869 if (spec->mono_nid > 0) {
2870 err = stac92xx_auto_create_mono_output_ctls(codec);
2871 if (err < 0)
2872 return err;
2873 }
2874
Matt Porter8b657272006-10-26 17:12:59 +02002875 if (spec->num_dmics > 0)
2876 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2877 &spec->autocfg)) < 0)
2878 return err;
2879
Mattc7d4b2f2005-06-27 14:59:41 +02002880 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002881 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002882 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002883
Takashi Iwai82bc9552006-03-21 11:24:42 +01002884 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002885 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002886 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002887 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002888
2889 if (spec->kctl_alloc)
2890 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2891
2892 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002893 if (!spec->dinput_mux)
2894 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002895 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002896
2897 return 1;
2898}
2899
Takashi Iwai82bc9552006-03-21 11:24:42 +01002900/* add playback controls for HP output */
2901static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2902 struct auto_pin_cfg *cfg)
2903{
2904 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002905 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002906 unsigned int wid_caps;
2907
2908 if (! pin)
2909 return 0;
2910
2911 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002912 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002913 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002914
2915 return 0;
2916}
2917
Richard Fish160ea0d2006-09-06 13:58:25 +02002918/* add playback controls for LFE output */
2919static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2920 struct auto_pin_cfg *cfg)
2921{
2922 struct sigmatel_spec *spec = codec->spec;
2923 int err;
2924 hda_nid_t lfe_pin = 0x0;
2925 int i;
2926
2927 /*
2928 * search speaker outs and line outs for a mono speaker pin
2929 * with an amp. If one is found, add LFE controls
2930 * for it.
2931 */
2932 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2933 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002934 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002935 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2936 if (wcaps == AC_WCAP_OUT_AMP)
2937 /* found a mono speaker with an amp, must be lfe */
2938 lfe_pin = pin;
2939 }
2940
2941 /* if speaker_outs is 0, then speakers may be in line_outs */
2942 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2943 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2944 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002945 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01002946 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02002947 AC_VERB_GET_CONFIG_DEFAULT,
2948 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01002949 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002950 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002951 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2952 if (wcaps == AC_WCAP_OUT_AMP)
2953 /* found a mono speaker with an amp,
2954 must be lfe */
2955 lfe_pin = pin;
2956 }
2957 }
2958 }
2959
2960 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002961 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002962 if (err < 0)
2963 return err;
2964 }
2965
2966 return 0;
2967}
2968
Mattc7d4b2f2005-06-27 14:59:41 +02002969static int stac9200_parse_auto_config(struct hda_codec *codec)
2970{
2971 struct sigmatel_spec *spec = codec->spec;
2972 int err;
2973
Kailang Yangdf694da2005-12-05 19:42:22 +01002974 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002975 return err;
2976
2977 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2978 return err;
2979
Takashi Iwai82bc9552006-03-21 11:24:42 +01002980 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2981 return err;
2982
Richard Fish160ea0d2006-09-06 13:58:25 +02002983 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2984 return err;
2985
Takashi Iwai82bc9552006-03-21 11:24:42 +01002986 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002987 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002988 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002989 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002990
2991 if (spec->kctl_alloc)
2992 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2993
2994 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002995 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002996
2997 return 1;
2998}
2999
Sam Revitch62fe78e2006-05-10 15:09:17 +02003000/*
3001 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3002 * funky external mute control using GPIO pins.
3003 */
3004
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003005static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003006 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003007{
3008 unsigned int gpiostate, gpiomask, gpiodir;
3009
3010 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3011 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003012 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003013
3014 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3015 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003016 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003017
3018 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3019 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003020 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003021
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003022 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003023 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3024
3025 snd_hda_codec_write(codec, codec->afg, 0,
3026 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003027 snd_hda_codec_read(codec, codec->afg, 0,
3028 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003029
3030 msleep(1);
3031
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003032 snd_hda_codec_read(codec, codec->afg, 0,
3033 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003034}
3035
Takashi Iwai314634b2006-09-21 11:56:18 +02003036static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3037 unsigned int event)
3038{
3039 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003040 snd_hda_codec_write_cache(codec, nid, 0,
3041 AC_VERB_SET_UNSOLICITED_ENABLE,
3042 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003043}
3044
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003045static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3046{
3047 int i;
3048 for (i = 0; i < cfg->hp_outs; i++)
3049 if (cfg->hp_pins[i] == nid)
3050 return 1; /* nid is a HP-Out */
3051
3052 return 0; /* nid is not a HP-Out */
3053};
3054
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003055static void stac92xx_power_down(struct hda_codec *codec)
3056{
3057 struct sigmatel_spec *spec = codec->spec;
3058
3059 /* power down inactive DACs */
3060 hda_nid_t *dac;
3061 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003062 if (!is_in_dac_nids(spec, *dac) &&
3063 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003064 snd_hda_codec_write_cache(codec, *dac, 0,
3065 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3066}
3067
Mattc7d4b2f2005-06-27 14:59:41 +02003068static int stac92xx_init(struct hda_codec *codec)
3069{
3070 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003071 struct auto_pin_cfg *cfg = &spec->autocfg;
3072 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003073
Mattc7d4b2f2005-06-27 14:59:41 +02003074 snd_hda_sequence_write(codec, spec->init);
3075
Takashi Iwai82bc9552006-03-21 11:24:42 +01003076 /* set up pins */
3077 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003078 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003079 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003080 enable_pin_detect(codec, cfg->hp_pins[i],
3081 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003082 /* force to enable the first line-out; the others are set up
3083 * in unsol_event
3084 */
3085 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3086 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003087 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003088 /* fake event to set up pins */
3089 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3090 } else {
3091 stac92xx_auto_init_multi_out(codec);
3092 stac92xx_auto_init_hp_out(codec);
3093 }
3094 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003095 hda_nid_t nid = cfg->input_pins[i];
3096 if (nid) {
3097 unsigned int pinctl = AC_PINCTL_IN_EN;
3098 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3099 pinctl |= stac92xx_get_vref(codec, nid);
3100 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3101 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003102 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003103 for (i = 0; i < spec->num_dmics; i++)
3104 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3105 AC_PINCTL_IN_EN);
3106 for (i = 0; i < spec->num_pwrs; i++) {
3107 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3108 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3109 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3110 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003111 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3112 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003113 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003114 /* outputs are only ports capable of power management
3115 * any attempts on powering down a input port cause the
3116 * referenced VREF to act quirky.
3117 */
3118 if (pinctl & AC_PINCTL_IN_EN)
3119 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003120 /* skip any ports that don't have jacks since presence
3121 * detection is useless */
3122 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003123 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003124 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3125 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3126 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003127 if (spec->dac_list)
3128 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003129 if (cfg->dig_out_pin)
3130 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3131 AC_PINCTL_OUT_EN);
3132 if (cfg->dig_in_pin)
3133 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3134 AC_PINCTL_IN_EN);
3135
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003136 stac_gpio_set(codec, spec->gpio_mask,
3137 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003138
Mattc7d4b2f2005-06-27 14:59:41 +02003139 return 0;
3140}
3141
Matt2f2f4252005-04-13 14:45:30 +02003142static void stac92xx_free(struct hda_codec *codec)
3143{
Mattc7d4b2f2005-06-27 14:59:41 +02003144 struct sigmatel_spec *spec = codec->spec;
3145 int i;
3146
3147 if (! spec)
3148 return;
3149
3150 if (spec->kctl_alloc) {
3151 for (i = 0; i < spec->num_kctl_used; i++)
3152 kfree(spec->kctl_alloc[i].name);
3153 kfree(spec->kctl_alloc);
3154 }
3155
Richard Fish11b44bb2006-08-23 18:31:34 +02003156 if (spec->bios_pin_configs)
3157 kfree(spec->bios_pin_configs);
3158
Mattc7d4b2f2005-06-27 14:59:41 +02003159 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02003160}
3161
Matt4e550962005-07-04 17:51:39 +02003162static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3163 unsigned int flag)
3164{
3165 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3166 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003167
Takashi Iwaif9acba42007-05-29 18:01:06 +02003168 if (pin_ctl & AC_PINCTL_IN_EN) {
3169 /*
3170 * we need to check the current set-up direction of
3171 * shared input pins since they can be switched via
3172 * "xxx as Output" mixer switch
3173 */
3174 struct sigmatel_spec *spec = codec->spec;
3175 struct auto_pin_cfg *cfg = &spec->autocfg;
3176 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3177 spec->line_switch) ||
3178 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3179 spec->mic_switch))
3180 return;
3181 }
3182
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003183 /* if setting pin direction bits, clear the current
3184 direction bits first */
3185 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3186 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3187
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003188 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003189 AC_VERB_SET_PIN_WIDGET_CONTROL,
3190 pin_ctl | flag);
3191}
3192
3193static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3194 unsigned int flag)
3195{
3196 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3197 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003198 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003199 AC_VERB_SET_PIN_WIDGET_CONTROL,
3200 pin_ctl & ~flag);
3201}
3202
Jiang Zhe40c1d302007-11-12 13:05:16 +01003203static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003204{
3205 if (!nid)
3206 return 0;
3207 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003208 & (1 << 31)) {
3209 unsigned int pinctl;
3210 pinctl = snd_hda_codec_read(codec, nid, 0,
3211 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3212 if (pinctl & AC_PINCTL_IN_EN)
3213 return 0; /* mic- or line-input */
3214 else
3215 return 1; /* HP-output */
3216 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003217 return 0;
3218}
3219
3220static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003221{
3222 struct sigmatel_spec *spec = codec->spec;
3223 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003224 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003225 int i, presence;
3226
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003227 presence = 0;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003228 if (spec->gpio_mute)
3229 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3230 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3231
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003232 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003233 if (presence)
3234 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003235 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3236 break;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003237 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003238 }
Matt4e550962005-07-04 17:51:39 +02003239
3240 if (presence) {
3241 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003242 if (spec->hp_switch)
3243 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003244 for (i = 0; i < cfg->line_outs; i++)
3245 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3246 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003247 for (i = 0; i < cfg->speaker_outs; i++)
3248 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3249 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003250 if (spec->eapd_mask)
3251 stac_gpio_set(codec, spec->gpio_mask,
3252 spec->gpio_dir, spec->gpio_data &
3253 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003254 } else {
3255 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003256 if (spec->hp_switch)
3257 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003258 for (i = 0; i < cfg->line_outs; i++)
3259 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3260 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003261 for (i = 0; i < cfg->speaker_outs; i++)
3262 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3263 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003264 if (spec->eapd_mask)
3265 stac_gpio_set(codec, spec->gpio_mask,
3266 spec->gpio_dir, spec->gpio_data |
3267 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003268 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003269 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3270 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003271}
3272
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003273static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3274{
3275 struct sigmatel_spec *spec = codec->spec;
3276 hda_nid_t nid = spec->pwr_nids[idx];
3277 int presence, val;
3278 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3279 & 0x000000ff;
3280 presence = get_hp_pin_presence(codec, nid);
3281 idx = 1 << idx;
3282
3283 if (presence)
3284 val &= ~idx;
3285 else
3286 val |= idx;
3287
3288 /* power down unused output ports */
3289 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3290};
3291
Takashi Iwai314634b2006-09-21 11:56:18 +02003292static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3293{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003294 struct sigmatel_spec *spec = codec->spec;
3295 int idx = res >> 26 & 0x0f;
3296
3297 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003298 case STAC_HP_EVENT:
3299 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003300 /* fallthru */
3301 case STAC_PWR_EVENT:
3302 if (spec->num_pwrs > 0)
3303 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003304 }
3305}
3306
Takashi Iwaicb53c622007-08-10 17:21:45 +02003307#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003308static int stac92xx_resume(struct hda_codec *codec)
3309{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003310 struct sigmatel_spec *spec = codec->spec;
3311
Richard Fish11b44bb2006-08-23 18:31:34 +02003312 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003313 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003314 stac_gpio_set(codec, spec->gpio_mask,
3315 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003316 snd_hda_codec_resume_amp(codec);
3317 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003318 /* power down inactive DACs */
3319 if (spec->dac_list)
3320 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003321 /* invoke unsolicited event to reset the HP state */
3322 if (spec->hp_detect)
3323 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003324 return 0;
3325}
3326#endif
3327
Matt2f2f4252005-04-13 14:45:30 +02003328static struct hda_codec_ops stac92xx_patch_ops = {
3329 .build_controls = stac92xx_build_controls,
3330 .build_pcms = stac92xx_build_pcms,
3331 .init = stac92xx_init,
3332 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003333 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003334#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003335 .resume = stac92xx_resume,
3336#endif
Matt2f2f4252005-04-13 14:45:30 +02003337};
3338
3339static int patch_stac9200(struct hda_codec *codec)
3340{
3341 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003342 int err;
Matt2f2f4252005-04-13 14:45:30 +02003343
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003344 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003345 if (spec == NULL)
3346 return -ENOMEM;
3347
3348 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003349 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003350 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003351 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3352 stac9200_models,
3353 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003354 if (spec->board_config < 0) {
3355 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3356 err = stac92xx_save_bios_config_regs(codec);
3357 if (err < 0) {
3358 stac92xx_free(codec);
3359 return err;
3360 }
3361 spec->pin_configs = spec->bios_pin_configs;
3362 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003363 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3364 stac92xx_set_config_regs(codec);
3365 }
Matt2f2f4252005-04-13 14:45:30 +02003366
3367 spec->multiout.max_channels = 2;
3368 spec->multiout.num_dacs = 1;
3369 spec->multiout.dac_nids = stac9200_dac_nids;
3370 spec->adc_nids = stac9200_adc_nids;
3371 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003372 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003373 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003374 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003375 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003376
Tobin Davisbf277782008-02-03 20:31:47 +01003377 if (spec->board_config == STAC_9200_GATEWAY ||
3378 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003379 spec->init = stac9200_eapd_init;
3380 else
3381 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003382 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003383
Takashi Iwai117f2572008-03-18 09:53:23 +01003384 if (spec->board_config == STAC_9200_PANASONIC) {
3385 spec->gpio_mask = spec->gpio_dir = 0x09;
3386 spec->gpio_data = 0x00;
3387 }
3388
Mattc7d4b2f2005-06-27 14:59:41 +02003389 err = stac9200_parse_auto_config(codec);
3390 if (err < 0) {
3391 stac92xx_free(codec);
3392 return err;
3393 }
Matt2f2f4252005-04-13 14:45:30 +02003394
3395 codec->patch_ops = stac92xx_patch_ops;
3396
3397 return 0;
3398}
3399
Tobin Davis8e21c342007-01-08 11:04:17 +01003400static int patch_stac925x(struct hda_codec *codec)
3401{
3402 struct sigmatel_spec *spec;
3403 int err;
3404
3405 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3406 if (spec == NULL)
3407 return -ENOMEM;
3408
3409 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003410 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003411 spec->pin_nids = stac925x_pin_nids;
3412 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3413 stac925x_models,
3414 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003415 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003416 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003417 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3418 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003419 err = stac92xx_save_bios_config_regs(codec);
3420 if (err < 0) {
3421 stac92xx_free(codec);
3422 return err;
3423 }
3424 spec->pin_configs = spec->bios_pin_configs;
3425 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3426 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3427 stac92xx_set_config_regs(codec);
3428 }
3429
3430 spec->multiout.max_channels = 2;
3431 spec->multiout.num_dacs = 1;
3432 spec->multiout.dac_nids = stac925x_dac_nids;
3433 spec->adc_nids = stac925x_adc_nids;
3434 spec->mux_nids = stac925x_mux_nids;
3435 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003436 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003437 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003438 switch (codec->vendor_id) {
3439 case 0x83847632: /* STAC9202 */
3440 case 0x83847633: /* STAC9202D */
3441 case 0x83847636: /* STAC9251 */
3442 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003443 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003444 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003445 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3446 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003447 break;
3448 default:
3449 spec->num_dmics = 0;
3450 break;
3451 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003452
3453 spec->init = stac925x_core_init;
3454 spec->mixer = stac925x_mixer;
3455
3456 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003457 if (!err) {
3458 if (spec->board_config < 0) {
3459 printk(KERN_WARNING "hda_codec: No auto-config is "
3460 "available, default to model=ref\n");
3461 spec->board_config = STAC_925x_REF;
3462 goto again;
3463 }
3464 err = -EINVAL;
3465 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003466 if (err < 0) {
3467 stac92xx_free(codec);
3468 return err;
3469 }
3470
3471 codec->patch_ops = stac92xx_patch_ops;
3472
3473 return 0;
3474}
3475
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003476static struct hda_input_mux stac92hd73xx_dmux = {
3477 .num_items = 4,
3478 .items = {
3479 { "Analog Inputs", 0x0b },
3480 { "CD", 0x08 },
3481 { "Digital Mic 1", 0x09 },
3482 { "Digital Mic 2", 0x0a },
3483 }
3484};
3485
3486static int patch_stac92hd73xx(struct hda_codec *codec)
3487{
3488 struct sigmatel_spec *spec;
3489 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3490 int err = 0;
3491
3492 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3493 if (spec == NULL)
3494 return -ENOMEM;
3495
3496 codec->spec = spec;
3497 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3498 spec->pin_nids = stac92hd73xx_pin_nids;
3499 spec->board_config = snd_hda_check_board_config(codec,
3500 STAC_92HD73XX_MODELS,
3501 stac92hd73xx_models,
3502 stac92hd73xx_cfg_tbl);
3503again:
3504 if (spec->board_config < 0) {
3505 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3506 " STAC92HD73XX, using BIOS defaults\n");
3507 err = stac92xx_save_bios_config_regs(codec);
3508 if (err < 0) {
3509 stac92xx_free(codec);
3510 return err;
3511 }
3512 spec->pin_configs = spec->bios_pin_configs;
3513 } else {
3514 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3515 stac92xx_set_config_regs(codec);
3516 }
3517
3518 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3519 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3520
3521 if (spec->multiout.num_dacs < 0) {
3522 printk(KERN_WARNING "hda_codec: Could not determine "
3523 "number of channels defaulting to DAC count\n");
3524 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3525 }
3526
3527 switch (spec->multiout.num_dacs) {
3528 case 0x3: /* 6 Channel */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003529 spec->multiout.hp_nid = 0x17;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003530 spec->mixer = stac92hd73xx_6ch_mixer;
3531 spec->init = stac92hd73xx_6ch_core_init;
3532 break;
3533 case 0x4: /* 8 Channel */
3534 spec->multiout.hp_nid = 0x18;
3535 spec->mixer = stac92hd73xx_8ch_mixer;
3536 spec->init = stac92hd73xx_8ch_core_init;
3537 break;
3538 case 0x5: /* 10 Channel */
3539 spec->multiout.hp_nid = 0x19;
3540 spec->mixer = stac92hd73xx_10ch_mixer;
3541 spec->init = stac92hd73xx_10ch_core_init;
3542 };
3543
3544 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3545 spec->aloopback_mask = 0x01;
3546 spec->aloopback_shift = 8;
3547
3548 spec->mux_nids = stac92hd73xx_mux_nids;
3549 spec->adc_nids = stac92hd73xx_adc_nids;
3550 spec->dmic_nids = stac92hd73xx_dmic_nids;
3551 spec->dmux_nids = stac92hd73xx_dmux_nids;
3552
3553 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3554 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003555 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003556 spec->dinput_mux = &stac92hd73xx_dmux;
3557 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003558 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003559 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003560
Matthew Ranostaya7662642008-02-21 07:51:14 +01003561 switch (spec->board_config) {
3562 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003563 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003564 switch (codec->subsystem_id) {
3565 case 0x1028025e: /* Analog Mics */
3566 case 0x1028025f:
3567 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3568 spec->num_dmics = 0;
3569 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003570 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003571 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003572 spec->init = dell_m6_core_init;
3573 /* fall-through */
3574 case 0x10280254:
3575 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003576 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3577 spec->num_dmics = 1;
3578 break;
3579 case 0x10280256: /* Both */
3580 case 0x10280057:
3581 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3582 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3583 spec->num_dmics = 1;
3584 break;
3585 }
3586 break;
3587 default:
3588 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3589 }
3590
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003591 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3592 spec->pwr_nids = stac92hd73xx_pwr_nids;
3593
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003594 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3595
3596 if (!err) {
3597 if (spec->board_config < 0) {
3598 printk(KERN_WARNING "hda_codec: No auto-config is "
3599 "available, default to model=ref\n");
3600 spec->board_config = STAC_92HD73XX_REF;
3601 goto again;
3602 }
3603 err = -EINVAL;
3604 }
3605
3606 if (err < 0) {
3607 stac92xx_free(codec);
3608 return err;
3609 }
3610
3611 codec->patch_ops = stac92xx_patch_ops;
3612
3613 return 0;
3614}
3615
Matthew Ranostaye035b842007-11-06 11:53:55 +01003616static int patch_stac92hd71bxx(struct hda_codec *codec)
3617{
3618 struct sigmatel_spec *spec;
3619 int err = 0;
3620
3621 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3622 if (spec == NULL)
3623 return -ENOMEM;
3624
3625 codec->spec = spec;
3626 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003627 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003628 spec->pin_nids = stac92hd71bxx_pin_nids;
3629 spec->board_config = snd_hda_check_board_config(codec,
3630 STAC_92HD71BXX_MODELS,
3631 stac92hd71bxx_models,
3632 stac92hd71bxx_cfg_tbl);
3633again:
3634 if (spec->board_config < 0) {
3635 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3636 " STAC92HD71BXX, using BIOS defaults\n");
3637 err = stac92xx_save_bios_config_regs(codec);
3638 if (err < 0) {
3639 stac92xx_free(codec);
3640 return err;
3641 }
3642 spec->pin_configs = spec->bios_pin_configs;
3643 } else {
3644 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3645 stac92xx_set_config_regs(codec);
3646 }
3647
Matthew Ranostay541eee82007-12-14 12:08:04 +01003648 switch (codec->vendor_id) {
3649 case 0x111d76b6: /* 4 Port without Analog Mixer */
3650 case 0x111d76b7:
3651 case 0x111d76b4: /* 6 Port without Analog Mixer */
3652 case 0x111d76b5:
3653 spec->mixer = stac92hd71bxx_mixer;
3654 spec->init = stac92hd71bxx_core_init;
3655 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003656 case 0x111d7608: /* 5 Port with Analog Mixer */
3657 /* no output amps */
3658 spec->num_pwrs = 0;
3659 spec->mixer = stac92hd71bxx_analog_mixer;
3660
3661 /* disable VSW */
3662 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
3663 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
3664 break;
3665 case 0x111d7603: /* 6 Port with Analog Mixer */
3666 /* no output amps */
3667 spec->num_pwrs = 0;
3668 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01003669 default:
3670 spec->mixer = stac92hd71bxx_analog_mixer;
3671 spec->init = stac92hd71bxx_analog_core_init;
3672 }
3673
3674 spec->aloopback_mask = 0x20;
3675 spec->aloopback_shift = 0;
3676
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003677 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003678 spec->gpio_mask = 0x01;
3679 spec->gpio_dir = 0x01;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003680 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003681
Matthew Ranostaye035b842007-11-06 11:53:55 +01003682 spec->mux_nids = stac92hd71bxx_mux_nids;
3683 spec->adc_nids = stac92hd71bxx_adc_nids;
3684 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003685 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003686 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003687
3688 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3689 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3690 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003691 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003692
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01003693 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003694 spec->multiout.hp_nid = 0x11;
3695 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3696
3697 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3698 if (!err) {
3699 if (spec->board_config < 0) {
3700 printk(KERN_WARNING "hda_codec: No auto-config is "
3701 "available, default to model=ref\n");
3702 spec->board_config = STAC_92HD71BXX_REF;
3703 goto again;
3704 }
3705 err = -EINVAL;
3706 }
3707
3708 if (err < 0) {
3709 stac92xx_free(codec);
3710 return err;
3711 }
3712
3713 codec->patch_ops = stac92xx_patch_ops;
3714
3715 return 0;
3716};
3717
Matt2f2f4252005-04-13 14:45:30 +02003718static int patch_stac922x(struct hda_codec *codec)
3719{
3720 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003721 int err;
Matt2f2f4252005-04-13 14:45:30 +02003722
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003723 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003724 if (spec == NULL)
3725 return -ENOMEM;
3726
3727 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003728 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003729 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003730 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3731 stac922x_models,
3732 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08003733 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003734 spec->gpio_mask = spec->gpio_dir = 0x03;
3735 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003736 /* Intel Macs have all same PCI SSID, so we need to check
3737 * codec SSID to distinguish the exact models
3738 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003739 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003740 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003741
3742 case 0x106b0800:
3743 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003744 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003745 case 0x106b0600:
3746 case 0x106b0700:
3747 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003748 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003749 case 0x106b0e00:
3750 case 0x106b0f00:
3751 case 0x106b1600:
3752 case 0x106b1700:
3753 case 0x106b0200:
3754 case 0x106b1e00:
3755 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003756 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003757 case 0x106b1a00:
3758 case 0x00000100:
3759 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003760 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003761 case 0x106b0a00:
3762 case 0x106b2200:
3763 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003764 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08003765 default:
3766 spec->board_config = STAC_INTEL_MAC_V3;
3767 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003768 }
3769 }
3770
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003771 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003772 if (spec->board_config < 0) {
3773 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3774 "using BIOS defaults\n");
3775 err = stac92xx_save_bios_config_regs(codec);
3776 if (err < 0) {
3777 stac92xx_free(codec);
3778 return err;
3779 }
3780 spec->pin_configs = spec->bios_pin_configs;
3781 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003782 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3783 stac92xx_set_config_regs(codec);
3784 }
Matt2f2f4252005-04-13 14:45:30 +02003785
Matt2f2f4252005-04-13 14:45:30 +02003786 spec->adc_nids = stac922x_adc_nids;
3787 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003788 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003789 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003790 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003791 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003792
3793 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003794 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003795
3796 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003797
Matt Porter3cc08dc2006-01-23 15:27:49 +01003798 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003799 if (!err) {
3800 if (spec->board_config < 0) {
3801 printk(KERN_WARNING "hda_codec: No auto-config is "
3802 "available, default to model=ref\n");
3803 spec->board_config = STAC_D945_REF;
3804 goto again;
3805 }
3806 err = -EINVAL;
3807 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003808 if (err < 0) {
3809 stac92xx_free(codec);
3810 return err;
3811 }
3812
3813 codec->patch_ops = stac92xx_patch_ops;
3814
Takashi Iwai807a46362007-05-29 19:01:37 +02003815 /* Fix Mux capture level; max to 2 */
3816 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3817 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3818 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3819 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3820 (0 << AC_AMPCAP_MUTE_SHIFT));
3821
Matt Porter3cc08dc2006-01-23 15:27:49 +01003822 return 0;
3823}
3824
3825static int patch_stac927x(struct hda_codec *codec)
3826{
3827 struct sigmatel_spec *spec;
3828 int err;
3829
3830 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3831 if (spec == NULL)
3832 return -ENOMEM;
3833
3834 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003835 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003836 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003837 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3838 stac927x_models,
3839 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003840 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003841 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3842 if (spec->board_config < 0)
3843 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3844 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003845 err = stac92xx_save_bios_config_regs(codec);
3846 if (err < 0) {
3847 stac92xx_free(codec);
3848 return err;
3849 }
3850 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003851 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003852 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3853 stac92xx_set_config_regs(codec);
3854 }
3855
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003856 spec->adc_nids = stac927x_adc_nids;
3857 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3858 spec->mux_nids = stac927x_mux_nids;
3859 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003860 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003861 spec->multiout.dac_nids = spec->dac_nids;
3862
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003863 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003864 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003865 case STAC_D965_5ST:
3866 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003867 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003868 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003869 spec->num_dmics = 0;
3870
Tobin Davis93ed1502006-09-01 21:03:12 +02003871 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003872 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003873 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003874 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02003875 switch (codec->subsystem_id) {
3876 case 0x10280209:
3877 case 0x1028022e:
3878 /* correct the device field to SPDIF out */
3879 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
3880 break;
3881 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003882 /* configure the analog microphone on some laptops */
3883 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003884 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003885 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003886 /* correct the front input jack as a mic */
3887 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3888 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003889 case STAC_DELL_3ST:
3890 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003891 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003892 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003893 spec->dmic_nids = stac927x_dmic_nids;
3894 spec->num_dmics = STAC927X_NUM_DMICS;
3895
Tobin Davis93ed1502006-09-01 21:03:12 +02003896 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003897 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003898 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003899 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003900 break;
3901 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003902 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003903 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003904 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003905 spec->num_dmics = 0;
3906
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003907 spec->init = stac927x_core_init;
3908 spec->mixer = stac927x_mixer;
3909 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003910
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003911 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003912 spec->aloopback_mask = 0x40;
3913 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003914
Matt Porter3cc08dc2006-01-23 15:27:49 +01003915 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003916 if (!err) {
3917 if (spec->board_config < 0) {
3918 printk(KERN_WARNING "hda_codec: No auto-config is "
3919 "available, default to model=ref\n");
3920 spec->board_config = STAC_D965_REF;
3921 goto again;
3922 }
3923 err = -EINVAL;
3924 }
Mattc7d4b2f2005-06-27 14:59:41 +02003925 if (err < 0) {
3926 stac92xx_free(codec);
3927 return err;
3928 }
Matt2f2f4252005-04-13 14:45:30 +02003929
3930 codec->patch_ops = stac92xx_patch_ops;
3931
Takashi Iwai52987652008-01-16 16:09:47 +01003932 /*
3933 * !!FIXME!!
3934 * The STAC927x seem to require fairly long delays for certain
3935 * command sequences. With too short delays (even if the answer
3936 * is set to RIRB properly), it results in the silence output
3937 * on some hardwares like Dell.
3938 *
3939 * The below flag enables the longer delay (see get_response
3940 * in hda_intel.c).
3941 */
3942 codec->bus->needs_damn_long_delay = 1;
3943
Matt2f2f4252005-04-13 14:45:30 +02003944 return 0;
3945}
3946
Matt Porterf3302a52006-07-31 12:49:34 +02003947static int patch_stac9205(struct hda_codec *codec)
3948{
3949 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003950 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003951
3952 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3953 if (spec == NULL)
3954 return -ENOMEM;
3955
3956 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003957 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003958 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003959 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3960 stac9205_models,
3961 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003962 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003963 if (spec->board_config < 0) {
3964 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3965 err = stac92xx_save_bios_config_regs(codec);
3966 if (err < 0) {
3967 stac92xx_free(codec);
3968 return err;
3969 }
3970 spec->pin_configs = spec->bios_pin_configs;
3971 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003972 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3973 stac92xx_set_config_regs(codec);
3974 }
3975
3976 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003977 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003978 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003979 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003980 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003981 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003982 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003983 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003984 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003985
3986 spec->init = stac9205_core_init;
3987 spec->mixer = stac9205_mixer;
3988
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003989 spec->aloopback_mask = 0x40;
3990 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003991 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003992
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003993 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003994 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003995 /* Enable SPDIF in/out */
3996 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3997 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003998
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003999 /* Enable unsol response for GPIO4/Dock HP connection */
4000 snd_hda_codec_write(codec, codec->afg, 0,
4001 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4002 snd_hda_codec_write_cache(codec, codec->afg, 0,
4003 AC_VERB_SET_UNSOLICITED_ENABLE,
4004 (AC_USRSP_EN | STAC_HP_EVENT));
4005
4006 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004007 spec->eapd_mask = 0x01;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004008 spec->gpio_mask = 0x1b;
4009 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004010 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004011 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004012 */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004013 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004014 break;
4015 default:
4016 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004017 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004018 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004019 break;
4020 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004021
Matt Porterf3302a52006-07-31 12:49:34 +02004022 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004023 if (!err) {
4024 if (spec->board_config < 0) {
4025 printk(KERN_WARNING "hda_codec: No auto-config is "
4026 "available, default to model=ref\n");
4027 spec->board_config = STAC_9205_REF;
4028 goto again;
4029 }
4030 err = -EINVAL;
4031 }
Matt Porterf3302a52006-07-31 12:49:34 +02004032 if (err < 0) {
4033 stac92xx_free(codec);
4034 return err;
4035 }
4036
4037 codec->patch_ops = stac92xx_patch_ops;
4038
4039 return 0;
4040}
4041
Matt2f2f4252005-04-13 14:45:30 +02004042/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004043 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004044 */
4045
Guillaume Munch99ccc562006-08-16 19:35:12 +02004046/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004047static hda_nid_t vaio_dacs[] = { 0x2 };
4048#define VAIO_HP_DAC 0x5
4049static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4050static hda_nid_t vaio_mux_nids[] = { 0x15 };
4051
4052static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004053 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004054 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004055 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004056 { "Mic Jack", 0x1 },
4057 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004058 { "PCM", 0x3 },
4059 }
4060};
4061
4062static struct hda_verb vaio_init[] = {
4063 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004064 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004065 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4066 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4067 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4068 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004069 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004070 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4071 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4072 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4073 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4074 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4075 {}
4076};
4077
Guillaume Munch6d859062006-08-22 17:15:47 +02004078static struct hda_verb vaio_ar_init[] = {
4079 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4080 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4081 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4082 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4083/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4084 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004085 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004086 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4087 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4088/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4089 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4090 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4091 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4092 {}
4093};
4094
Takashi Iwaidb064e52006-03-16 16:04:58 +01004095/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004096static struct hda_bind_ctls vaio_bind_master_vol = {
4097 .ops = &snd_hda_bind_vol,
4098 .values = {
4099 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4100 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4101 0
4102 },
4103};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004104
4105/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004106static struct hda_bind_ctls vaio_bind_master_sw = {
4107 .ops = &snd_hda_bind_sw,
4108 .values = {
4109 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4110 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4111 0,
4112 },
4113};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004114
4115static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004116 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4117 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004118 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4119 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4120 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4121 {
4122 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4123 .name = "Capture Source",
4124 .count = 1,
4125 .info = stac92xx_mux_enum_info,
4126 .get = stac92xx_mux_enum_get,
4127 .put = stac92xx_mux_enum_put,
4128 },
4129 {}
4130};
4131
Guillaume Munch6d859062006-08-22 17:15:47 +02004132static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004133 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4134 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004135 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4136 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4137 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4138 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4139 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4140 {
4141 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4142 .name = "Capture Source",
4143 .count = 1,
4144 .info = stac92xx_mux_enum_info,
4145 .get = stac92xx_mux_enum_get,
4146 .put = stac92xx_mux_enum_put,
4147 },
4148 {}
4149};
4150
4151static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004152 .build_controls = stac92xx_build_controls,
4153 .build_pcms = stac92xx_build_pcms,
4154 .init = stac92xx_init,
4155 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004156#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004157 .resume = stac92xx_resume,
4158#endif
4159};
4160
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004161static int stac9872_vaio_init(struct hda_codec *codec)
4162{
4163 int err;
4164
4165 err = stac92xx_init(codec);
4166 if (err < 0)
4167 return err;
4168 if (codec->patch_ops.unsol_event)
4169 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4170 return 0;
4171}
4172
4173static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4174{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004175 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004176 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4177 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4178 } else {
4179 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4180 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4181 }
4182}
4183
4184static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4185{
4186 switch (res >> 26) {
4187 case STAC_HP_EVENT:
4188 stac9872_vaio_hp_detect(codec, res);
4189 break;
4190 }
4191}
4192
4193static struct hda_codec_ops stac9872_vaio_patch_ops = {
4194 .build_controls = stac92xx_build_controls,
4195 .build_pcms = stac92xx_build_pcms,
4196 .init = stac9872_vaio_init,
4197 .free = stac92xx_free,
4198 .unsol_event = stac9872_vaio_unsol_event,
4199#ifdef CONFIG_PM
4200 .resume = stac92xx_resume,
4201#endif
4202};
4203
Guillaume Munch6d859062006-08-22 17:15:47 +02004204enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4205 CXD9872RD_VAIO,
4206 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4207 STAC9872AK_VAIO,
4208 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4209 STAC9872K_VAIO,
4210 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004211 CXD9872AKD_VAIO,
4212 STAC_9872_MODELS,
4213};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004214
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004215static const char *stac9872_models[STAC_9872_MODELS] = {
4216 [CXD9872RD_VAIO] = "vaio",
4217 [CXD9872AKD_VAIO] = "vaio-ar",
4218};
4219
4220static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4221 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4222 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4223 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004224 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004225 {}
4226};
4227
Guillaume Munch6d859062006-08-22 17:15:47 +02004228static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004229{
4230 struct sigmatel_spec *spec;
4231 int board_config;
4232
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004233 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4234 stac9872_models,
4235 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004236 if (board_config < 0)
4237 /* unknown config, let generic-parser do its job... */
4238 return snd_hda_parse_generic_codec(codec);
4239
4240 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4241 if (spec == NULL)
4242 return -ENOMEM;
4243
4244 codec->spec = spec;
4245 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004246 case CXD9872RD_VAIO:
4247 case STAC9872AK_VAIO:
4248 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004249 spec->mixer = vaio_mixer;
4250 spec->init = vaio_init;
4251 spec->multiout.max_channels = 2;
4252 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4253 spec->multiout.dac_nids = vaio_dacs;
4254 spec->multiout.hp_nid = VAIO_HP_DAC;
4255 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4256 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004257 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004258 spec->input_mux = &vaio_mux;
4259 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004260 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004261 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004262
4263 case CXD9872AKD_VAIO:
4264 spec->mixer = vaio_ar_mixer;
4265 spec->init = vaio_ar_init;
4266 spec->multiout.max_channels = 2;
4267 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4268 spec->multiout.dac_nids = vaio_dacs;
4269 spec->multiout.hp_nid = VAIO_HP_DAC;
4270 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004271 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004272 spec->adc_nids = vaio_adcs;
4273 spec->input_mux = &vaio_mux;
4274 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004275 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004276 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004277 }
4278
Takashi Iwaidb064e52006-03-16 16:04:58 +01004279 return 0;
4280}
4281
4282
4283/*
Matt2f2f4252005-04-13 14:45:30 +02004284 * patch entries
4285 */
4286struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4287 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4288 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4289 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4290 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4291 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4292 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4293 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004294 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4295 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4296 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4297 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4298 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4299 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004300 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4301 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4302 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4303 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4304 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4305 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4306 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4307 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4308 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4309 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004310 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4311 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4312 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4313 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4314 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4315 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02004316 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
4317 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004318 /* The following does not take into account .id=0x83847661 when subsys =
4319 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4320 * currently not fully supported.
4321 */
4322 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4323 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4324 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004325 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4326 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4327 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4328 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4329 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4330 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4331 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4332 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004333 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
4334 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01004335 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4336 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004337 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004338 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4339 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4340 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4341 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4342 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4343 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4344 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4345 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004346 {} /* terminator */
4347};