blob: 6ee73ed23dddc14e99011ee04dea46598d6b5dbe [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"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020036#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020037
Matt4e550962005-07-04 17:51:39 +020038#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010039#define STAC_PWR_EVENT 0x20
40#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020041
Takashi Iwaif5fcc132006-11-24 17:07:44 +010042enum {
43 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010044 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020045 STAC_9200_DELL_D21,
46 STAC_9200_DELL_D22,
47 STAC_9200_DELL_D23,
48 STAC_9200_DELL_M21,
49 STAC_9200_DELL_M22,
50 STAC_9200_DELL_M23,
51 STAC_9200_DELL_M24,
52 STAC_9200_DELL_M25,
53 STAC_9200_DELL_M26,
54 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020055 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010056 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010057 STAC_9200_MODELS
58};
59
60enum {
61 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020062 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020063 STAC_9205_DELL_M43,
64 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010065 STAC_9205_MODELS
66};
67
68enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010069 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010070 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010071 STAC_92HD73XX_MODELS
72};
73
74enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010075 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010076 STAC_DELL_M4_1,
77 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010078 STAC_92HD71BXX_MODELS
79};
80
81enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010082 STAC_925x_REF,
83 STAC_M2_2,
84 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020085 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010086 STAC_925x_MODELS
87};
88
89enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010090 STAC_D945_REF,
91 STAC_D945GTP3,
92 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020093 STAC_INTEL_MAC_V1,
94 STAC_INTEL_MAC_V2,
95 STAC_INTEL_MAC_V3,
96 STAC_INTEL_MAC_V4,
97 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +080098 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
99 * is given, one of the above models will be
100 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200101 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100102 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100103 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100104 STAC_MACBOOK_PRO_V1,
105 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200106 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200107 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200108 STAC_922X_DELL_D81,
109 STAC_922X_DELL_D82,
110 STAC_922X_DELL_M81,
111 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100112 STAC_922X_MODELS
113};
114
115enum {
116 STAC_D965_REF,
117 STAC_D965_3ST,
118 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200119 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100120 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100121 STAC_927X_MODELS
122};
Matt Porter403d1942005-11-29 15:00:51 +0100123
Matt2f2f4252005-04-13 14:45:30 +0200124struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100125 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200126 unsigned int num_mixers;
127
Matt Porter403d1942005-11-29 15:00:51 +0100128 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200129 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100130 unsigned int line_switch: 1;
131 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100132 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100133 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200134
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100135 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200136 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100137 unsigned int gpio_mask;
138 unsigned int gpio_dir;
139 unsigned int gpio_data;
140 unsigned int gpio_mute;
141
142 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100143 unsigned char aloopback_mask;
144 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200145
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100146 /* power management */
147 unsigned int num_pwrs;
148 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100149 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100150
Matt2f2f4252005-04-13 14:45:30 +0200151 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100152 struct hda_input_mux *mono_mux;
153 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200154 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100155 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200156
157 /* capture */
158 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200159 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200160 hda_nid_t *mux_nids;
161 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200162 hda_nid_t *dmic_nids;
163 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100164 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100165 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200166 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100167 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200168 hda_nid_t anabeep_nid;
169 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200170
Matt2f2f4252005-04-13 14:45:30 +0200171 /* pin widgets */
172 hda_nid_t *pin_nids;
173 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200174 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200175 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200176
177 /* codec specific stuff */
178 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100179 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200180
181 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200182 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100183 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200184 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100185 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200186
Matt Porter403d1942005-11-29 15:00:51 +0100187 /* i/o switches */
188 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200189 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200190 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200191 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200192
Mattc7d4b2f2005-06-27 14:59:41 +0200193 struct hda_pcm pcm_rec[2]; /* PCM information */
194
195 /* dynamic controls and input_mux */
196 struct auto_pin_cfg autocfg;
197 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100198 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200199 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200200 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100201 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200202};
203
204static hda_nid_t stac9200_adc_nids[1] = {
205 0x03,
206};
207
208static hda_nid_t stac9200_mux_nids[1] = {
209 0x0c,
210};
211
212static hda_nid_t stac9200_dac_nids[1] = {
213 0x02,
214};
215
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100216static hda_nid_t stac92hd73xx_pwr_nids[8] = {
217 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
218 0x0f, 0x10, 0x11
219};
220
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100221static hda_nid_t stac92hd73xx_adc_nids[2] = {
222 0x1a, 0x1b
223};
224
225#define STAC92HD73XX_NUM_DMICS 2
226static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
227 0x13, 0x14, 0
228};
229
230#define STAC92HD73_DAC_COUNT 5
231static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
232 0x15, 0x16, 0x17, 0x18, 0x19,
233};
234
235static hda_nid_t stac92hd73xx_mux_nids[4] = {
236 0x28, 0x29, 0x2a, 0x2b,
237};
238
239static hda_nid_t stac92hd73xx_dmux_nids[2] = {
240 0x20, 0x21,
241};
242
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100243static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
244 0x0a, 0x0d, 0x0f
245};
246
Matthew Ranostaye035b842007-11-06 11:53:55 +0100247static hda_nid_t stac92hd71bxx_adc_nids[2] = {
248 0x12, 0x13,
249};
250
251static hda_nid_t stac92hd71bxx_mux_nids[2] = {
252 0x1a, 0x1b
253};
254
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100255static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
256 0x1c,
257};
258
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100259static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100260 0x10, /*0x11, */
261};
262
263#define STAC92HD71BXX_NUM_DMICS 2
264static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
265 0x18, 0x19, 0
266};
267
Tobin Davis8e21c342007-01-08 11:04:17 +0100268static hda_nid_t stac925x_adc_nids[1] = {
269 0x03,
270};
271
272static hda_nid_t stac925x_mux_nids[1] = {
273 0x0f,
274};
275
276static hda_nid_t stac925x_dac_nids[1] = {
277 0x02,
278};
279
Takashi Iwaif6e98522007-10-16 14:27:04 +0200280#define STAC925X_NUM_DMICS 1
281static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
282 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200283};
284
Takashi Iwai1697055e2007-12-18 18:05:52 +0100285static hda_nid_t stac925x_dmux_nids[1] = {
286 0x14,
287};
288
Matt2f2f4252005-04-13 14:45:30 +0200289static hda_nid_t stac922x_adc_nids[2] = {
290 0x06, 0x07,
291};
292
293static hda_nid_t stac922x_mux_nids[2] = {
294 0x12, 0x13,
295};
296
Matt Porter3cc08dc2006-01-23 15:27:49 +0100297static hda_nid_t stac927x_adc_nids[3] = {
298 0x07, 0x08, 0x09
299};
300
301static hda_nid_t stac927x_mux_nids[3] = {
302 0x15, 0x16, 0x17
303};
304
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100305static hda_nid_t stac927x_dac_nids[6] = {
306 0x02, 0x03, 0x04, 0x05, 0x06, 0
307};
308
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100309static hda_nid_t stac927x_dmux_nids[1] = {
310 0x1b,
311};
312
Matthew Ranostay7f168592007-10-18 17:38:17 +0200313#define STAC927X_NUM_DMICS 2
314static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
315 0x13, 0x14, 0
316};
317
Matt Porterf3302a52006-07-31 12:49:34 +0200318static hda_nid_t stac9205_adc_nids[2] = {
319 0x12, 0x13
320};
321
322static hda_nid_t stac9205_mux_nids[2] = {
323 0x19, 0x1a
324};
325
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100326static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100327 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100328};
329
Takashi Iwaif6e98522007-10-16 14:27:04 +0200330#define STAC9205_NUM_DMICS 2
331static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
332 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200333};
334
Mattc7d4b2f2005-06-27 14:59:41 +0200335static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200336 0x08, 0x09, 0x0d, 0x0e,
337 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200338};
339
Tobin Davis8e21c342007-01-08 11:04:17 +0100340static hda_nid_t stac925x_pin_nids[8] = {
341 0x07, 0x08, 0x0a, 0x0b,
342 0x0c, 0x0d, 0x10, 0x11,
343};
344
Matt2f2f4252005-04-13 14:45:30 +0200345static hda_nid_t stac922x_pin_nids[10] = {
346 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
347 0x0f, 0x10, 0x11, 0x15, 0x1b,
348};
349
Matthew Ranostaya7662642008-02-21 07:51:14 +0100350static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100351 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
352 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100353 0x14, 0x1e, 0x22
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100354};
355
Matthew Ranostaye035b842007-11-06 11:53:55 +0100356static hda_nid_t stac92hd71bxx_pin_nids[10] = {
357 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
358 0x0f, 0x14, 0x18, 0x19, 0x1e,
359};
360
Matt Porter3cc08dc2006-01-23 15:27:49 +0100361static hda_nid_t stac927x_pin_nids[14] = {
362 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
363 0x0f, 0x10, 0x11, 0x12, 0x13,
364 0x14, 0x21, 0x22, 0x23,
365};
366
Matt Porterf3302a52006-07-31 12:49:34 +0200367static hda_nid_t stac9205_pin_nids[12] = {
368 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
369 0x0f, 0x14, 0x16, 0x17, 0x18,
370 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200371};
372
Matt Porter8b657272006-10-26 17:12:59 +0200373static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
374 struct snd_ctl_elem_info *uinfo)
375{
376 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
377 struct sigmatel_spec *spec = codec->spec;
378 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
379}
380
381static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
382 struct snd_ctl_elem_value *ucontrol)
383{
384 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
385 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100386 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200387
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100388 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200389 return 0;
390}
391
392static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
393 struct snd_ctl_elem_value *ucontrol)
394{
395 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
396 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100397 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200398
399 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100400 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200401}
402
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100403static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200404{
405 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
406 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200407 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200408}
409
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100410static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200411{
412 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
413 struct sigmatel_spec *spec = codec->spec;
414 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
415
416 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
417 return 0;
418}
419
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100420static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200421{
422 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
423 struct sigmatel_spec *spec = codec->spec;
424 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
425
Mattc7d4b2f2005-06-27 14:59:41 +0200426 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200427 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
428}
429
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100430static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_info *uinfo)
432{
433 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
434 struct sigmatel_spec *spec = codec->spec;
435 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
436}
437
438static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_value *ucontrol)
440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
442 struct sigmatel_spec *spec = codec->spec;
443
444 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
445 return 0;
446}
447
448static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
449 struct snd_ctl_elem_value *ucontrol)
450{
451 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
452 struct sigmatel_spec *spec = codec->spec;
453
454 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
455 spec->mono_nid, &spec->cur_mmux);
456}
457
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200458#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
459
460static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
461 struct snd_ctl_elem_value *ucontrol)
462{
463 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100464 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200465 struct sigmatel_spec *spec = codec->spec;
466
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100467 ucontrol->value.integer.value[0] = !!(spec->aloopback &
468 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200469 return 0;
470}
471
472static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_value *ucontrol)
474{
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100477 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200478 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100479 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200480
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100481 idx_val = spec->aloopback_mask << idx;
482 if (ucontrol->value.integer.value[0])
483 val = spec->aloopback | idx_val;
484 else
485 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100486 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200487 return 0;
488
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100489 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200490
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100491 /* Only return the bits defined by the shift value of the
492 * first two bytes of the mask
493 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200494 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100495 kcontrol->private_value & 0xFFFF, 0x0);
496 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200497
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100498 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200499 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100500 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200501 } else {
502 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100503 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200504 }
505
506 snd_hda_codec_write_cache(codec, codec->afg, 0,
507 kcontrol->private_value >> 16, dac_mode);
508
509 return 1;
510}
511
Mattc7d4b2f2005-06-27 14:59:41 +0200512static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200513 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200514 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200515 {}
516};
517
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200518static struct hda_verb stac9200_eapd_init[] = {
519 /* set dac0mux for dac converter */
520 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
521 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
522 {}
523};
524
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100525static struct hda_verb stac92hd73xx_6ch_core_init[] = {
526 /* set master volume and direct control */
527 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
528 /* setup audio connections */
529 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
530 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
531 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
532 /* setup adcs to point to mixer */
533 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
534 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100535 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
536 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
537 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
538 /* setup import muxs */
539 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
540 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
541 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
542 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
543 {}
544};
545
Matthew Ranostayd654a662008-03-14 08:46:51 +0100546static struct hda_verb dell_eq_core_init[] = {
547 /* set master volume to max value without distortion
548 * and direct control */
549 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
550 /* setup audio connections */
551 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
552 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
553 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
554 /* setup adcs to point to mixer */
555 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
556 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
557 /* setup import muxs */
558 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
559 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
560 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
561 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
562 {}
563};
564
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100565static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay20f5f952008-09-01 08:17:56 +0200566 /* set master volume to max value without distortion
567 * and direct control */
568 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100569 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100570 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
571 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100572 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
573 /* setup adcs to point to mixer */
574 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
575 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
576 /* setup import muxs */
577 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
578 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
579 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
580 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
581 {}
582};
583
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100584static struct hda_verb stac92hd73xx_8ch_core_init[] = {
585 /* set master volume and direct control */
586 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
587 /* setup audio connections */
588 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
589 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
590 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
591 /* connect hp ports to dac3 */
592 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
593 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
594 /* setup adcs to point to mixer */
595 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
596 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100597 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
598 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
599 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
600 /* setup import muxs */
601 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
602 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
603 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
604 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
605 {}
606};
607
608static struct hda_verb stac92hd73xx_10ch_core_init[] = {
609 /* set master volume and direct control */
610 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
611 /* setup audio connections */
612 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
613 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
614 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
615 /* dac3 is connected to import3 mux */
616 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
617 /* connect hp ports to dac4 */
618 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
619 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
620 /* setup adcs to point to mixer */
621 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
622 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100623 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
624 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
625 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
626 /* setup import muxs */
627 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
628 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
629 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
630 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
631 {}
632};
633
Matthew Ranostaye035b842007-11-06 11:53:55 +0100634static struct hda_verb stac92hd71bxx_core_init[] = {
635 /* set master volume and direct control */
636 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
637 /* connect headphone jack to dac1 */
638 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100639 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
640 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
641 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
642 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
643 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100644};
645
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200646#define HD_DISABLE_PORTF 3
Matthew Ranostay541eee82007-12-14 12:08:04 +0100647static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200648 /* start of config #1 */
649
650 /* connect port 0f to audio mixer */
651 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
652 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
653 /* unmute right and left channels for node 0x0f */
654 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
655 /* start of config #2 */
656
Matthew Ranostay541eee82007-12-14 12:08:04 +0100657 /* set master volume and direct control */
658 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
659 /* connect headphone jack to dac1 */
660 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200661 /* connect port 0d to audio mixer */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100662 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100663 /* unmute dac0 input in audio mixer */
664 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200665 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100666 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
667 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100668 {}
669};
670
Tobin Davis8e21c342007-01-08 11:04:17 +0100671static struct hda_verb stac925x_core_init[] = {
672 /* set dac0mux for dac converter */
673 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
674 {}
675};
676
Mattc7d4b2f2005-06-27 14:59:41 +0200677static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200678 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200679 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200680 {}
681};
682
Tobin Davis93ed1502006-09-01 21:03:12 +0200683static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200684 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200685 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200686 /* unmute node 0x1b */
687 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
688 /* select node 0x03 as DAC */
689 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
690 {}
691};
692
Matt Porter3cc08dc2006-01-23 15:27:49 +0100693static struct hda_verb stac927x_core_init[] = {
694 /* set master volume and direct control */
695 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200696 /* enable analog pc beep path */
697 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100698 {}
699};
700
Matt Porterf3302a52006-07-31 12:49:34 +0200701static struct hda_verb stac9205_core_init[] = {
702 /* set master volume and direct control */
703 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
704 {}
705};
706
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100707#define STAC_MONO_MUX \
708 { \
709 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
710 .name = "Mono Mux", \
711 .count = 1, \
712 .info = stac92xx_mono_mux_enum_info, \
713 .get = stac92xx_mono_mux_enum_get, \
714 .put = stac92xx_mono_mux_enum_put, \
715 }
716
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200717#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200718 { \
719 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
720 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200721 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200722 .info = stac92xx_mux_enum_info, \
723 .get = stac92xx_mux_enum_get, \
724 .put = stac92xx_mux_enum_put, \
725 }
726
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100727#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200728 { \
729 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
730 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100731 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200732 .info = stac92xx_aloopback_info, \
733 .get = stac92xx_aloopback_get, \
734 .put = stac92xx_aloopback_put, \
735 .private_value = verb_read | (verb_write << 16), \
736 }
737
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100738static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200739 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
740 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200741 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200742 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
743 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200744 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200745 { } /* end */
746};
747
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100748static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100749 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
750
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100751 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
752 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
753
754 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
755 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
756
757 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
758 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
759
760 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
761 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
762
763 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
764 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
765
766 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
767 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
768
769 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
770 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
771 { } /* end */
772};
773
774static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100775 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
776
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100777 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
778 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
779
780 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
781 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
782
783 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
784 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
785
786 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
787 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
788
789 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
790 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
791
792 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
793 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
794
795 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
796 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
797 { } /* end */
798};
799
800static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100801 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
802
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100803 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
804 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
805
806 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
807 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
808
809 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
810 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
811
812 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
813 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
814
815 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
816 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
817
818 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
819 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
820
821 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
822 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
823 { } /* end */
824};
825
Matthew Ranostay541eee82007-12-14 12:08:04 +0100826static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100827 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100828
Matthew Ranostay9b359472007-11-07 13:03:12 +0100829 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
830 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
831 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
832
833 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
834 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
835 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
836
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200837 /* analog pc-beep replaced with digital beep support */
838 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200839 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
840 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200841 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +0200842
Matthew Ranostay9b359472007-11-07 13:03:12 +0100843 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
844 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100845 { } /* end */
846};
847
Matthew Ranostay541eee82007-12-14 12:08:04 +0100848static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100849 STAC_INPUT_SOURCE(2),
850 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
851
Matthew Ranostay541eee82007-12-14 12:08:04 +0100852 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
853 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
854 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
855
856 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
857 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
858 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
859 { } /* end */
860};
861
Tobin Davis8e21c342007-01-08 11:04:17 +0100862static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200863 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100864 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +0200865 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +0100866 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
867 { } /* end */
868};
869
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100870static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200871 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100872 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200873
874 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
875 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
876 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
877
878 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
879 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
880 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
881
882 { } /* end */
883};
884
885/* This needs to be generated dynamically based on sequence */
886static struct snd_kcontrol_new stac922x_mixer[] = {
887 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200888 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
889 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
890 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
891
892 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
893 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
894 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
895 { } /* end */
896};
897
898
899static struct snd_kcontrol_new stac927x_mixer[] = {
900 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100901 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200902
903 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
904 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
905 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
906
907 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
908 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
909 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
910
911 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
912 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
913 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200914 { } /* end */
915};
916
Takashi Iwai1697055e2007-12-18 18:05:52 +0100917static struct snd_kcontrol_new stac_dmux_mixer = {
918 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
919 .name = "Digital Input Source",
920 /* count set later */
921 .info = stac92xx_dmux_enum_info,
922 .get = stac92xx_dmux_enum_get,
923 .put = stac92xx_dmux_enum_put,
924};
925
Takashi Iwai2134ea42008-01-10 16:53:55 +0100926static const char *slave_vols[] = {
927 "Front Playback Volume",
928 "Surround Playback Volume",
929 "Center Playback Volume",
930 "LFE Playback Volume",
931 "Side Playback Volume",
932 "Headphone Playback Volume",
933 "Headphone Playback Volume",
934 "Speaker Playback Volume",
935 "External Speaker Playback Volume",
936 "Speaker2 Playback Volume",
937 NULL
938};
939
940static const char *slave_sws[] = {
941 "Front Playback Switch",
942 "Surround Playback Switch",
943 "Center Playback Switch",
944 "LFE Playback Switch",
945 "Side Playback Switch",
946 "Headphone Playback Switch",
947 "Headphone Playback Switch",
948 "Speaker Playback Switch",
949 "External Speaker Playback Switch",
950 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100951 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100952 NULL
953};
954
Matt2f2f4252005-04-13 14:45:30 +0200955static int stac92xx_build_controls(struct hda_codec *codec)
956{
957 struct sigmatel_spec *spec = codec->spec;
958 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200959 int i;
Matt2f2f4252005-04-13 14:45:30 +0200960
961 err = snd_hda_add_new_ctls(codec, spec->mixer);
962 if (err < 0)
963 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200964
965 for (i = 0; i < spec->num_mixers; i++) {
966 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
967 if (err < 0)
968 return err;
969 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100970 if (spec->num_dmuxes > 0) {
971 stac_dmux_mixer.count = spec->num_dmuxes;
972 err = snd_ctl_add(codec->bus->card,
973 snd_ctl_new1(&stac_dmux_mixer, codec));
974 if (err < 0)
975 return err;
976 }
Mattc7d4b2f2005-06-27 14:59:41 +0200977
Mattdabbed62005-06-14 10:19:34 +0200978 if (spec->multiout.dig_out_nid) {
979 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
980 if (err < 0)
981 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100982 err = snd_hda_create_spdif_share_sw(codec,
983 &spec->multiout);
984 if (err < 0)
985 return err;
986 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200987 }
988 if (spec->dig_in_nid) {
989 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
990 if (err < 0)
991 return err;
992 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100993
994 /* if we have no master control, let's create it */
995 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100996 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100997 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100998 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100999 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001000 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001001 if (err < 0)
1002 return err;
1003 }
1004 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1005 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1006 NULL, slave_sws);
1007 if (err < 0)
1008 return err;
1009 }
1010
Mattdabbed62005-06-14 10:19:34 +02001011 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001012}
1013
Matt Porter403d1942005-11-29 15:00:51 +01001014static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001015 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001016 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1017};
1018
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001019/*
1020 STAC 9200 pin configs for
1021 102801A8
1022 102801DE
1023 102801E8
1024*/
1025static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001026 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1027 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001028};
1029
1030/*
1031 STAC 9200 pin configs for
1032 102801C0
1033 102801C1
1034*/
1035static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001036 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1037 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001038};
1039
1040/*
1041 STAC 9200 pin configs for
1042 102801C4 (Dell Dimension E310)
1043 102801C5
1044 102801C7
1045 102801D9
1046 102801DA
1047 102801E3
1048*/
1049static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001050 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1051 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001052};
1053
1054
1055/*
1056 STAC 9200-32 pin configs for
1057 102801B5 (Dell Inspiron 630m)
1058 102801D8 (Dell Inspiron 640m)
1059*/
1060static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001061 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1062 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001063};
1064
1065/*
1066 STAC 9200-32 pin configs for
1067 102801C2 (Dell Latitude D620)
1068 102801C8
1069 102801CC (Dell Latitude D820)
1070 102801D4
1071 102801D6
1072*/
1073static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001074 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1075 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001076};
1077
1078/*
1079 STAC 9200-32 pin configs for
1080 102801CE (Dell XPS M1710)
1081 102801CF (Dell Precision M90)
1082*/
1083static unsigned int dell9200_m23_pin_configs[8] = {
1084 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1085 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1086};
1087
1088/*
1089 STAC 9200-32 pin configs for
1090 102801C9
1091 102801CA
1092 102801CB (Dell Latitude 120L)
1093 102801D3
1094*/
1095static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001096 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1097 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001098};
1099
1100/*
1101 STAC 9200-32 pin configs for
1102 102801BD (Dell Inspiron E1505n)
1103 102801EE
1104 102801EF
1105*/
1106static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001107 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1108 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001109};
1110
1111/*
1112 STAC 9200-32 pin configs for
1113 102801F5 (Dell Inspiron 1501)
1114 102801F6
1115*/
1116static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001117 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1118 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001119};
1120
1121/*
1122 STAC 9200-32
1123 102801CD (Dell Inspiron E1705/9400)
1124*/
1125static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001126 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1127 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001128};
1129
Tobin Davisbf277782008-02-03 20:31:47 +01001130static unsigned int oqo9200_pin_configs[8] = {
1131 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1132 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1133};
1134
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001135
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001136static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1137 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001138 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001139 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1140 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1141 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1142 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1143 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1144 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1145 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1146 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1147 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1148 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001149 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001150};
1151
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001152static const char *stac9200_models[STAC_9200_MODELS] = {
1153 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001154 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001155 [STAC_9200_DELL_D21] = "dell-d21",
1156 [STAC_9200_DELL_D22] = "dell-d22",
1157 [STAC_9200_DELL_D23] = "dell-d23",
1158 [STAC_9200_DELL_M21] = "dell-m21",
1159 [STAC_9200_DELL_M22] = "dell-m22",
1160 [STAC_9200_DELL_M23] = "dell-m23",
1161 [STAC_9200_DELL_M24] = "dell-m24",
1162 [STAC_9200_DELL_M25] = "dell-m25",
1163 [STAC_9200_DELL_M26] = "dell-m26",
1164 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001165 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001166 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001167};
1168
1169static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1170 /* SigmaTel reference board */
1171 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1172 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001173 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001174 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1175 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001176 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001177 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1178 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1179 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1180 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1181 "unknown Dell", STAC_9200_DELL_D22),
1182 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1183 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001184 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001185 "Dell Latitude D620", STAC_9200_DELL_M22),
1186 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1187 "unknown Dell", STAC_9200_DELL_D23),
1188 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1189 "unknown Dell", STAC_9200_DELL_D23),
1190 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1191 "unknown Dell", STAC_9200_DELL_M22),
1192 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1193 "unknown Dell", STAC_9200_DELL_M24),
1194 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1195 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001196 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001197 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001198 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001199 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001200 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001201 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001202 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001203 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001204 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001205 "Dell Precision M90", STAC_9200_DELL_M23),
1206 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1207 "unknown Dell", STAC_9200_DELL_M22),
1208 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1209 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001210 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001211 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001212 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001213 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1214 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1215 "unknown Dell", STAC_9200_DELL_D23),
1216 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1217 "unknown Dell", STAC_9200_DELL_D23),
1218 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1219 "unknown Dell", STAC_9200_DELL_D21),
1220 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1221 "unknown Dell", STAC_9200_DELL_D23),
1222 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1223 "unknown Dell", STAC_9200_DELL_D21),
1224 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1225 "unknown Dell", STAC_9200_DELL_M25),
1226 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1227 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001228 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001229 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1230 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1231 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001232 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001233 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001234 /* Gateway machines needs EAPD to be set on resume */
1235 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1236 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1237 STAC_9200_GATEWAY),
1238 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1239 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001240 /* OQO Mobile */
1241 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001242 {} /* terminator */
1243};
1244
Tobin Davis8e21c342007-01-08 11:04:17 +01001245static unsigned int ref925x_pin_configs[8] = {
1246 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001247 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001248};
1249
1250static unsigned int stac925x_MA6_pin_configs[8] = {
1251 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1252 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1253};
1254
Tobin Davis2c11f952007-05-17 09:36:34 +02001255static unsigned int stac925x_PA6_pin_configs[8] = {
1256 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1257 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1258};
1259
Tobin Davis8e21c342007-01-08 11:04:17 +01001260static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001261 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1262 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001263};
1264
1265static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1266 [STAC_REF] = ref925x_pin_configs,
1267 [STAC_M2_2] = stac925xM2_2_pin_configs,
1268 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001269 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001270};
1271
1272static const char *stac925x_models[STAC_925x_MODELS] = {
1273 [STAC_REF] = "ref",
1274 [STAC_M2_2] = "m2-2",
1275 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001276 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001277};
1278
1279static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1280 /* SigmaTel reference board */
1281 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001282 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001283 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1284 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1285 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001286 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001287 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1288 {} /* terminator */
1289};
1290
Matthew Ranostaya7662642008-02-21 07:51:14 +01001291static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001292 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1293 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1294 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001295 0x01452050,
1296};
1297
1298static unsigned int dell_m6_pin_configs[13] = {
1299 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001300 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001301 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1302 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001303};
1304
1305static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001306 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1307 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001308};
1309
1310static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1311 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001312 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001313};
1314
1315static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1316 /* SigmaTel reference board */
1317 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001318 "DFI LanParty", STAC_92HD73XX_REF),
1319 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1320 "unknown Dell", STAC_DELL_M6),
1321 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1322 "unknown Dell", STAC_DELL_M6),
1323 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1324 "unknown Dell", STAC_DELL_M6),
1325 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1326 "unknown Dell", STAC_DELL_M6),
1327 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1328 "unknown Dell", STAC_DELL_M6),
1329 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1330 "unknown Dell", STAC_DELL_M6),
1331 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1332 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001333 {} /* terminator */
1334};
1335
Matthew Ranostaye035b842007-11-06 11:53:55 +01001336static unsigned int ref92hd71bxx_pin_configs[10] = {
1337 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001338 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001339 0x90a000f0, 0x01452050,
1340};
1341
Matthew Ranostayaafc4412008-06-13 18:04:33 +02001342static unsigned int dell_m4_1_pin_configs[10] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001343 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001344 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001345 0x40f000f0, 0x4f0000f0,
1346};
1347
Matthew Ranostayaafc4412008-06-13 18:04:33 +02001348static unsigned int dell_m4_2_pin_configs[10] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001349 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1350 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1351 0x40f000f0, 0x044413b0,
1352};
1353
Matthew Ranostaye035b842007-11-06 11:53:55 +01001354static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1355 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001356 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1357 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001358};
1359
1360static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1361 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001362 [STAC_DELL_M4_1] = "dell-m4-1",
1363 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001364};
1365
1366static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1367 /* SigmaTel reference board */
1368 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1369 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001370 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1371 "unknown Dell", STAC_DELL_M4_1),
1372 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1373 "unknown Dell", STAC_DELL_M4_1),
1374 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1375 "unknown Dell", STAC_DELL_M4_1),
1376 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1377 "unknown Dell", STAC_DELL_M4_1),
1378 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1379 "unknown Dell", STAC_DELL_M4_1),
1380 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1381 "unknown Dell", STAC_DELL_M4_1),
1382 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1383 "unknown Dell", STAC_DELL_M4_1),
1384 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1385 "unknown Dell", STAC_DELL_M4_2),
1386 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1387 "unknown Dell", STAC_DELL_M4_2),
1388 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1389 "unknown Dell", STAC_DELL_M4_2),
1390 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1391 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001392 {} /* terminator */
1393};
1394
Matt Porter403d1942005-11-29 15:00:51 +01001395static unsigned int ref922x_pin_configs[10] = {
1396 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1397 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001398 0x40000100, 0x40000100,
1399};
1400
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001401/*
1402 STAC 922X pin configs for
1403 102801A7
1404 102801AB
1405 102801A9
1406 102801D1
1407 102801D2
1408*/
1409static unsigned int dell_922x_d81_pin_configs[10] = {
1410 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1411 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1412 0x01813122, 0x400001f2,
1413};
1414
1415/*
1416 STAC 922X pin configs for
1417 102801AC
1418 102801D0
1419*/
1420static unsigned int dell_922x_d82_pin_configs[10] = {
1421 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1422 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1423 0x01813122, 0x400001f1,
1424};
1425
1426/*
1427 STAC 922X pin configs for
1428 102801BF
1429*/
1430static unsigned int dell_922x_m81_pin_configs[10] = {
1431 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1432 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1433 0x40C003f1, 0x405003f0,
1434};
1435
1436/*
1437 STAC 9221 A1 pin configs for
1438 102801D7 (Dell XPS M1210)
1439*/
1440static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001441 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1442 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001443 0x508003f3, 0x405003f4,
1444};
1445
Matt Porter403d1942005-11-29 15:00:51 +01001446static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001447 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001448 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1449 0x02a19120, 0x40000100,
1450};
1451
1452static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001453 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1454 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001455 0x02a19320, 0x40000100,
1456};
1457
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001458static unsigned int intel_mac_v1_pin_configs[10] = {
1459 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1460 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001461 0x400000fc, 0x400000fb,
1462};
1463
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001464static unsigned int intel_mac_v2_pin_configs[10] = {
1465 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1466 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001467 0x400000fc, 0x400000fb,
1468};
1469
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001470static unsigned int intel_mac_v3_pin_configs[10] = {
1471 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1472 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1473 0x400000fc, 0x400000fb,
1474};
1475
1476static unsigned int intel_mac_v4_pin_configs[10] = {
1477 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1478 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1479 0x400000fc, 0x400000fb,
1480};
1481
1482static unsigned int intel_mac_v5_pin_configs[10] = {
1483 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1484 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1485 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001486};
1487
Takashi Iwai76c08822007-06-19 12:17:42 +02001488
Takashi Iwai19039bd2006-06-28 15:52:16 +02001489static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001490 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001491 [STAC_D945GTP3] = d945gtp3_pin_configs,
1492 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001493 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1494 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1495 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1496 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1497 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001498 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001499 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001500 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1501 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1502 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1503 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1504 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1505 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001506 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1507 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1508 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1509 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001510};
1511
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001512static const char *stac922x_models[STAC_922X_MODELS] = {
1513 [STAC_D945_REF] = "ref",
1514 [STAC_D945GTP5] = "5stack",
1515 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001516 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1517 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1518 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1519 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1520 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001521 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001522 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001523 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001524 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001525 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1526 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001527 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001528 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001529 [STAC_922X_DELL_D81] = "dell-d81",
1530 [STAC_922X_DELL_D82] = "dell-d82",
1531 [STAC_922X_DELL_M81] = "dell-m81",
1532 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001533};
1534
1535static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1536 /* SigmaTel reference board */
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1538 "DFI LanParty", STAC_D945_REF),
1539 /* Intel 945G based systems */
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1541 "Intel D945G", STAC_D945GTP3),
1542 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1543 "Intel D945G", STAC_D945GTP3),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1545 "Intel D945G", STAC_D945GTP3),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1547 "Intel D945G", STAC_D945GTP3),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1549 "Intel D945G", STAC_D945GTP3),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1551 "Intel D945G", STAC_D945GTP3),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1553 "Intel D945G", STAC_D945GTP3),
1554 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1555 "Intel D945G", STAC_D945GTP3),
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1557 "Intel D945G", STAC_D945GTP3),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1559 "Intel D945G", STAC_D945GTP3),
1560 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1561 "Intel D945G", STAC_D945GTP3),
1562 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1563 "Intel D945G", STAC_D945GTP3),
1564 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1565 "Intel D945G", STAC_D945GTP3),
1566 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1567 "Intel D945G", STAC_D945GTP3),
1568 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1569 "Intel D945G", STAC_D945GTP3),
1570 /* Intel D945G 5-stack systems */
1571 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1572 "Intel D945G", STAC_D945GTP5),
1573 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1574 "Intel D945G", STAC_D945GTP5),
1575 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1576 "Intel D945G", STAC_D945GTP5),
1577 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1578 "Intel D945G", STAC_D945GTP5),
1579 /* Intel 945P based systems */
1580 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1581 "Intel D945P", STAC_D945GTP3),
1582 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1583 "Intel D945P", STAC_D945GTP3),
1584 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1585 "Intel D945P", STAC_D945GTP3),
1586 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1587 "Intel D945P", STAC_D945GTP3),
1588 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1589 "Intel D945P", STAC_D945GTP3),
1590 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1591 "Intel D945P", STAC_D945GTP5),
1592 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001593 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001594 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001595 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001596 /* Dell systems */
1597 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1598 "unknown Dell", STAC_922X_DELL_D81),
1599 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1600 "unknown Dell", STAC_922X_DELL_D81),
1601 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1602 "unknown Dell", STAC_922X_DELL_D81),
1603 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1604 "unknown Dell", STAC_922X_DELL_D82),
1605 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1606 "unknown Dell", STAC_922X_DELL_M81),
1607 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1608 "unknown Dell", STAC_922X_DELL_D82),
1609 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1610 "unknown Dell", STAC_922X_DELL_D81),
1611 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1612 "unknown Dell", STAC_922X_DELL_D81),
1613 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1614 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001615 {} /* terminator */
1616};
1617
Matt Porter3cc08dc2006-01-23 15:27:49 +01001618static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001619 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1620 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1621 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1622 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001623};
1624
Tobin Davis93ed1502006-09-01 21:03:12 +02001625static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001626 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1627 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1628 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1629 0x40000100, 0x40000100
1630};
1631
Tobin Davis93ed1502006-09-01 21:03:12 +02001632static unsigned int d965_5st_pin_configs[14] = {
1633 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1634 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1635 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1636 0x40000100, 0x40000100
1637};
1638
Tobin Davis4ff076e2007-08-07 11:48:12 +02001639static unsigned int dell_3st_pin_configs[14] = {
1640 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1641 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001642 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001643 0x40c003fc, 0x40000100
1644};
1645
Tobin Davis93ed1502006-09-01 21:03:12 +02001646static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001647 [STAC_D965_REF] = ref927x_pin_configs,
1648 [STAC_D965_3ST] = d965_3st_pin_configs,
1649 [STAC_D965_5ST] = d965_5st_pin_configs,
1650 [STAC_DELL_3ST] = dell_3st_pin_configs,
1651 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001652};
1653
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001654static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001655 [STAC_D965_REF] = "ref",
1656 [STAC_D965_3ST] = "3stack",
1657 [STAC_D965_5ST] = "5stack",
1658 [STAC_DELL_3ST] = "dell-3stack",
1659 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001660};
1661
1662static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1663 /* SigmaTel reference board */
1664 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1665 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001666 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001667 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1668 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001669 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001670 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1671 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1672 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1674 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1675 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1676 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1677 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1678 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1679 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1680 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1681 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1682 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1683 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1684 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1685 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001686 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001687 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001688 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001689 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1690 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001691 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001692 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1693 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001694 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02001695 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001696 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1697 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1698 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1699 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001700 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001701 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1702 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1703 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1704 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1705 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1706 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1707 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1708 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1709 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001710 {} /* terminator */
1711};
1712
Matt Porterf3302a52006-07-31 12:49:34 +02001713static unsigned int ref9205_pin_configs[12] = {
1714 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001715 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001716 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001717};
1718
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001719/*
1720 STAC 9205 pin configs for
1721 102801F1
1722 102801F2
1723 102801FC
1724 102801FD
1725 10280204
1726 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001727 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001728*/
1729static unsigned int dell_9205_m42_pin_configs[12] = {
1730 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1731 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1732 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1733};
1734
1735/*
1736 STAC 9205 pin configs for
1737 102801F9
1738 102801FA
1739 102801FE
1740 102801FF (Dell Precision M4300)
1741 10280206
1742 10280200
1743 10280201
1744*/
1745static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001746 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1747 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1748 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1749};
1750
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001751static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001752 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1753 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1754 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1755};
1756
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001757static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001758 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001759 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1760 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1761 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001762};
1763
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001764static const char *stac9205_models[STAC_9205_MODELS] = {
1765 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001766 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001767 [STAC_9205_DELL_M43] = "dell-m43",
1768 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001769};
1770
1771static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1772 /* SigmaTel reference board */
1773 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1774 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001775 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1776 "unknown Dell", STAC_9205_DELL_M42),
1777 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1778 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001779 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001780 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001781 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1782 "Dell Precision", STAC_9205_DELL_M43),
1783 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1784 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001785 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1786 "unknown Dell", STAC_9205_DELL_M42),
1787 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1788 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001789 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1790 "Dell Precision", STAC_9205_DELL_M43),
1791 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001792 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001793 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1794 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02001795 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1796 "Dell Precision", STAC_9205_DELL_M43),
1797 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1798 "Dell Precision", STAC_9205_DELL_M43),
1799 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1800 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001801 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1802 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001803 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1804 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001805 {} /* terminator */
1806};
1807
Richard Fish11b44bb2006-08-23 18:31:34 +02001808static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1809{
1810 int i;
1811 struct sigmatel_spec *spec = codec->spec;
1812
1813 if (! spec->bios_pin_configs) {
1814 spec->bios_pin_configs = kcalloc(spec->num_pins,
1815 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1816 if (! spec->bios_pin_configs)
1817 return -ENOMEM;
1818 }
1819
1820 for (i = 0; i < spec->num_pins; i++) {
1821 hda_nid_t nid = spec->pin_nids[i];
1822 unsigned int pin_cfg;
1823
1824 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1825 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1826 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1827 nid, pin_cfg);
1828 spec->bios_pin_configs[i] = pin_cfg;
1829 }
1830
1831 return 0;
1832}
1833
Matthew Ranostay87d48362007-07-17 11:52:24 +02001834static void stac92xx_set_config_reg(struct hda_codec *codec,
1835 hda_nid_t pin_nid, unsigned int pin_config)
1836{
1837 int i;
1838 snd_hda_codec_write(codec, pin_nid, 0,
1839 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1840 pin_config & 0x000000ff);
1841 snd_hda_codec_write(codec, pin_nid, 0,
1842 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1843 (pin_config & 0x0000ff00) >> 8);
1844 snd_hda_codec_write(codec, pin_nid, 0,
1845 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1846 (pin_config & 0x00ff0000) >> 16);
1847 snd_hda_codec_write(codec, pin_nid, 0,
1848 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1849 pin_config >> 24);
1850 i = snd_hda_codec_read(codec, pin_nid, 0,
1851 AC_VERB_GET_CONFIG_DEFAULT,
1852 0x00);
1853 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1854 pin_nid, i);
1855}
1856
Matt2f2f4252005-04-13 14:45:30 +02001857static void stac92xx_set_config_regs(struct hda_codec *codec)
1858{
1859 int i;
1860 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001861
Matthew Ranostay87d48362007-07-17 11:52:24 +02001862 if (!spec->pin_configs)
1863 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001864
Matthew Ranostay87d48362007-07-17 11:52:24 +02001865 for (i = 0; i < spec->num_pins; i++)
1866 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1867 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001868}
Matt2f2f4252005-04-13 14:45:30 +02001869
Matt2f2f4252005-04-13 14:45:30 +02001870/*
1871 * Analog playback callbacks
1872 */
1873static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1874 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001875 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001876{
1877 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001878 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1879 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001880}
1881
1882static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1883 struct hda_codec *codec,
1884 unsigned int stream_tag,
1885 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001886 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001887{
1888 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001889 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001890}
1891
1892static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1893 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001894 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001895{
1896 struct sigmatel_spec *spec = codec->spec;
1897 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1898}
1899
1900/*
Mattdabbed62005-06-14 10:19:34 +02001901 * Digital playback callbacks
1902 */
1903static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1904 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001905 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001906{
1907 struct sigmatel_spec *spec = codec->spec;
1908 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1909}
1910
1911static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1912 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001913 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001914{
1915 struct sigmatel_spec *spec = codec->spec;
1916 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1917}
1918
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001919static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1920 struct hda_codec *codec,
1921 unsigned int stream_tag,
1922 unsigned int format,
1923 struct snd_pcm_substream *substream)
1924{
1925 struct sigmatel_spec *spec = codec->spec;
1926 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1927 stream_tag, format, substream);
1928}
1929
Mattdabbed62005-06-14 10:19:34 +02001930
1931/*
Matt2f2f4252005-04-13 14:45:30 +02001932 * Analog capture callbacks
1933 */
1934static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1935 struct hda_codec *codec,
1936 unsigned int stream_tag,
1937 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001938 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001939{
1940 struct sigmatel_spec *spec = codec->spec;
1941
1942 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1943 stream_tag, 0, format);
1944 return 0;
1945}
1946
1947static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1948 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001949 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001950{
1951 struct sigmatel_spec *spec = codec->spec;
1952
Takashi Iwai888afa12008-03-18 09:57:50 +01001953 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Matt2f2f4252005-04-13 14:45:30 +02001954 return 0;
1955}
1956
Mattdabbed62005-06-14 10:19:34 +02001957static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1958 .substreams = 1,
1959 .channels_min = 2,
1960 .channels_max = 2,
1961 /* NID is set in stac92xx_build_pcms */
1962 .ops = {
1963 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001964 .close = stac92xx_dig_playback_pcm_close,
1965 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001966 },
1967};
1968
1969static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1970 .substreams = 1,
1971 .channels_min = 2,
1972 .channels_max = 2,
1973 /* NID is set in stac92xx_build_pcms */
1974};
1975
Matt2f2f4252005-04-13 14:45:30 +02001976static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1977 .substreams = 1,
1978 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001979 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001980 .nid = 0x02, /* NID to query formats and rates */
1981 .ops = {
1982 .open = stac92xx_playback_pcm_open,
1983 .prepare = stac92xx_playback_pcm_prepare,
1984 .cleanup = stac92xx_playback_pcm_cleanup
1985 },
1986};
1987
Matt Porter3cc08dc2006-01-23 15:27:49 +01001988static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1989 .substreams = 1,
1990 .channels_min = 2,
1991 .channels_max = 2,
1992 .nid = 0x06, /* NID to query formats and rates */
1993 .ops = {
1994 .open = stac92xx_playback_pcm_open,
1995 .prepare = stac92xx_playback_pcm_prepare,
1996 .cleanup = stac92xx_playback_pcm_cleanup
1997 },
1998};
1999
Matt2f2f4252005-04-13 14:45:30 +02002000static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002001 .channels_min = 2,
2002 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002003 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002004 .ops = {
2005 .prepare = stac92xx_capture_pcm_prepare,
2006 .cleanup = stac92xx_capture_pcm_cleanup
2007 },
2008};
2009
2010static int stac92xx_build_pcms(struct hda_codec *codec)
2011{
2012 struct sigmatel_spec *spec = codec->spec;
2013 struct hda_pcm *info = spec->pcm_rec;
2014
2015 codec->num_pcms = 1;
2016 codec->pcm_info = info;
2017
Mattc7d4b2f2005-06-27 14:59:41 +02002018 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002019 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002020 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002021 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002022 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002023
2024 if (spec->alt_switch) {
2025 codec->num_pcms++;
2026 info++;
2027 info->name = "STAC92xx Analog Alt";
2028 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2029 }
Matt2f2f4252005-04-13 14:45:30 +02002030
Mattdabbed62005-06-14 10:19:34 +02002031 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2032 codec->num_pcms++;
2033 info++;
2034 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002035 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002036 if (spec->multiout.dig_out_nid) {
2037 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2038 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2039 }
2040 if (spec->dig_in_nid) {
2041 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2042 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2043 }
2044 }
2045
Matt2f2f4252005-04-13 14:45:30 +02002046 return 0;
2047}
2048
Takashi Iwaic960a032006-03-23 17:06:28 +01002049static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2050{
2051 unsigned int pincap = snd_hda_param_read(codec, nid,
2052 AC_PAR_PIN_CAP);
2053 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2054 if (pincap & AC_PINCAP_VREF_100)
2055 return AC_PINCTL_VREF_100;
2056 if (pincap & AC_PINCAP_VREF_80)
2057 return AC_PINCTL_VREF_80;
2058 if (pincap & AC_PINCAP_VREF_50)
2059 return AC_PINCTL_VREF_50;
2060 if (pincap & AC_PINCAP_VREF_GRD)
2061 return AC_PINCTL_VREF_GRD;
2062 return 0;
2063}
2064
Matt Porter403d1942005-11-29 15:00:51 +01002065static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2066
2067{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002068 snd_hda_codec_write_cache(codec, nid, 0,
2069 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002070}
2071
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002072#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2073
2074static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2075 struct snd_ctl_elem_value *ucontrol)
2076{
2077 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2078 struct sigmatel_spec *spec = codec->spec;
2079
2080 ucontrol->value.integer.value[0] = spec->hp_switch;
2081 return 0;
2082}
2083
2084static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2085 struct snd_ctl_elem_value *ucontrol)
2086{
2087 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2088 struct sigmatel_spec *spec = codec->spec;
2089
2090 spec->hp_switch = ucontrol->value.integer.value[0];
2091
2092 /* check to be sure that the ports are upto date with
2093 * switch changes
2094 */
2095 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2096
2097 return 1;
2098}
2099
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002100#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002101
2102static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2103{
2104 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2105 struct sigmatel_spec *spec = codec->spec;
2106 int io_idx = kcontrol-> private_value & 0xff;
2107
2108 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2109 return 0;
2110}
2111
2112static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2113{
2114 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2115 struct sigmatel_spec *spec = codec->spec;
2116 hda_nid_t nid = kcontrol->private_value >> 8;
2117 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002118 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002119
2120 spec->io_switch[io_idx] = val;
2121
2122 if (val)
2123 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002124 else {
2125 unsigned int pinctl = AC_PINCTL_IN_EN;
2126 if (io_idx) /* set VREF for mic */
2127 pinctl |= stac92xx_get_vref(codec, nid);
2128 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2129 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002130
2131 /* check the auto-mute again: we need to mute/unmute the speaker
2132 * appropriately according to the pin direction
2133 */
2134 if (spec->hp_detect)
2135 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2136
Matt Porter403d1942005-11-29 15:00:51 +01002137 return 1;
2138}
2139
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002140#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2141
2142static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2143 struct snd_ctl_elem_value *ucontrol)
2144{
2145 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2146 struct sigmatel_spec *spec = codec->spec;
2147
2148 ucontrol->value.integer.value[0] = spec->clfe_swap;
2149 return 0;
2150}
2151
2152static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2153 struct snd_ctl_elem_value *ucontrol)
2154{
2155 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2156 struct sigmatel_spec *spec = codec->spec;
2157 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002158 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002159
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002160 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002161 return 0;
2162
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002163 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002164
2165 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2166 spec->clfe_swap ? 0x4 : 0x0);
2167
2168 return 1;
2169}
2170
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002171#define STAC_CODEC_HP_SWITCH(xname) \
2172 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2173 .name = xname, \
2174 .index = 0, \
2175 .info = stac92xx_hp_switch_info, \
2176 .get = stac92xx_hp_switch_get, \
2177 .put = stac92xx_hp_switch_put, \
2178 }
2179
Matt Porter403d1942005-11-29 15:00:51 +01002180#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2181 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2182 .name = xname, \
2183 .index = 0, \
2184 .info = stac92xx_io_switch_info, \
2185 .get = stac92xx_io_switch_get, \
2186 .put = stac92xx_io_switch_put, \
2187 .private_value = xpval, \
2188 }
2189
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002190#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2191 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2192 .name = xname, \
2193 .index = 0, \
2194 .info = stac92xx_clfe_switch_info, \
2195 .get = stac92xx_clfe_switch_get, \
2196 .put = stac92xx_clfe_switch_put, \
2197 .private_value = xpval, \
2198 }
Matt Porter403d1942005-11-29 15:00:51 +01002199
Mattc7d4b2f2005-06-27 14:59:41 +02002200enum {
2201 STAC_CTL_WIDGET_VOL,
2202 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002203 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002204 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002205 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002206 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002207};
2208
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002209static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002210 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2211 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002212 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002213 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002214 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002215 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002216};
2217
2218/* add dynamic controls */
2219static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2220{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002221 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002222
2223 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2224 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2225
2226 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2227 if (! knew)
2228 return -ENOMEM;
2229 if (spec->kctl_alloc) {
2230 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2231 kfree(spec->kctl_alloc);
2232 }
2233 spec->kctl_alloc = knew;
2234 spec->num_kctl_alloc = num;
2235 }
2236
2237 knew = &spec->kctl_alloc[spec->num_kctl_used];
2238 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002239 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002240 if (! knew->name)
2241 return -ENOMEM;
2242 knew->private_value = val;
2243 spec->num_kctl_used++;
2244 return 0;
2245}
2246
Matt Porter403d1942005-11-29 15:00:51 +01002247/* flag inputs as additional dynamic lineouts */
2248static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2249{
2250 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002251 unsigned int wcaps, wtype;
2252 int i, num_dacs = 0;
2253
2254 /* use the wcaps cache to count all DACs available for line-outs */
2255 for (i = 0; i < codec->num_nodes; i++) {
2256 wcaps = codec->wcaps[i];
2257 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002258
Steve Longerbeam7b043892007-05-03 20:50:03 +02002259 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2260 num_dacs++;
2261 }
Matt Porter403d1942005-11-29 15:00:51 +01002262
Steve Longerbeam7b043892007-05-03 20:50:03 +02002263 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2264
Matt Porter403d1942005-11-29 15:00:51 +01002265 switch (cfg->line_outs) {
2266 case 3:
2267 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002268 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
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 }
2274 break;
2275 case 2:
2276 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002277 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002278 cfg->line_out_pins[cfg->line_outs] =
2279 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002280 spec->line_switch = 1;
2281 cfg->line_outs++;
2282 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002283 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002284 cfg->line_out_pins[cfg->line_outs] =
2285 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002286 spec->mic_switch = 1;
2287 cfg->line_outs++;
2288 }
2289 break;
2290 case 1:
2291 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002292 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002293 cfg->line_out_pins[cfg->line_outs] =
2294 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002295 spec->line_switch = 1;
2296 cfg->line_outs++;
2297 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002298 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002299 cfg->line_out_pins[cfg->line_outs] =
2300 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002301 spec->mic_switch = 1;
2302 cfg->line_outs++;
2303 }
2304 break;
2305 }
2306
2307 return 0;
2308}
2309
Steve Longerbeam7b043892007-05-03 20:50:03 +02002310
2311static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2312{
2313 int i;
2314
2315 for (i = 0; i < spec->multiout.num_dacs; i++) {
2316 if (spec->multiout.dac_nids[i] == nid)
2317 return 1;
2318 }
2319
2320 return 0;
2321}
2322
Matt Porter3cc08dc2006-01-23 15:27:49 +01002323/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002324 * Fill in the dac_nids table from the parsed pin configuration
2325 * This function only works when every pin in line_out_pins[]
2326 * contains atleast one DAC in its connection list. Some 92xx
2327 * codecs are not connected directly to a DAC, such as the 9200
2328 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002329 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002330static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002331 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002332{
2333 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002334 int i, j, conn_len = 0;
2335 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2336 unsigned int wcaps, wtype;
2337
Mattc7d4b2f2005-06-27 14:59:41 +02002338 for (i = 0; i < cfg->line_outs; i++) {
2339 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002340 conn_len = snd_hda_get_connections(codec, nid, conn,
2341 HDA_MAX_CONNECTIONS);
2342 for (j = 0; j < conn_len; j++) {
2343 wcaps = snd_hda_param_read(codec, conn[j],
2344 AC_PAR_AUDIO_WIDGET_CAP);
2345 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002346 if (wtype != AC_WID_AUD_OUT ||
2347 (wcaps & AC_WCAP_DIGITAL))
2348 continue;
2349 /* conn[j] is a DAC routed to this line-out */
2350 if (!is_in_dac_nids(spec, conn[j]))
2351 break;
2352 }
2353
2354 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002355 if (spec->multiout.num_dacs > 0) {
2356 /* we have already working output pins,
2357 * so let's drop the broken ones again
2358 */
2359 cfg->line_outs = spec->multiout.num_dacs;
2360 break;
2361 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002362 /* error out, no available DAC found */
2363 snd_printk(KERN_ERR
2364 "%s: No available DAC for pin 0x%x\n",
2365 __func__, nid);
2366 return -ENODEV;
2367 }
2368
2369 spec->multiout.dac_nids[i] = conn[j];
2370 spec->multiout.num_dacs++;
2371 if (conn_len > 1) {
2372 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002373 snd_hda_codec_write_cache(codec, nid, 0,
2374 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002375
2376 }
Mattc7d4b2f2005-06-27 14:59:41 +02002377 }
2378
Steve Longerbeam7b043892007-05-03 20:50:03 +02002379 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2380 spec->multiout.num_dacs,
2381 spec->multiout.dac_nids[0],
2382 spec->multiout.dac_nids[1],
2383 spec->multiout.dac_nids[2],
2384 spec->multiout.dac_nids[3],
2385 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002386 return 0;
2387}
2388
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002389/* create volume control/switch for the given prefx type */
2390static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2391{
2392 char name[32];
2393 int err;
2394
2395 sprintf(name, "%s Playback Volume", pfx);
2396 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2397 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2398 if (err < 0)
2399 return err;
2400 sprintf(name, "%s Playback Switch", pfx);
2401 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2402 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2403 if (err < 0)
2404 return err;
2405 return 0;
2406}
2407
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002408static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2409{
2410 if (!spec->multiout.hp_nid)
2411 spec->multiout.hp_nid = nid;
2412 else if (spec->multiout.num_dacs > 4) {
2413 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2414 return 1;
2415 } else {
2416 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2417 spec->multiout.num_dacs++;
2418 }
2419 return 0;
2420}
2421
2422static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2423{
2424 if (is_in_dac_nids(spec, nid))
2425 return 1;
2426 if (spec->multiout.hp_nid == nid)
2427 return 1;
2428 return 0;
2429}
2430
Mattc7d4b2f2005-06-27 14:59:41 +02002431/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002432static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002433 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002434{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002435 static const char *chname[4] = {
2436 "Front", "Surround", NULL /*CLFE*/, "Side"
2437 };
Mattc7d4b2f2005-06-27 14:59:41 +02002438 hda_nid_t nid;
2439 int i, err;
2440
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002441 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002442 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002443
2444
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002445 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002446 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002447 continue;
2448
2449 nid = spec->multiout.dac_nids[i];
2450
2451 if (i == 2) {
2452 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002453 err = create_controls(spec, "Center", nid, 1);
2454 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002455 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002456 err = create_controls(spec, "LFE", nid, 2);
2457 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002458 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002459
2460 wid_caps = get_wcaps(codec, nid);
2461
2462 if (wid_caps & AC_WCAP_LR_SWAP) {
2463 err = stac92xx_add_control(spec,
2464 STAC_CTL_WIDGET_CLFE_SWITCH,
2465 "Swap Center/LFE Playback Switch", nid);
2466
2467 if (err < 0)
2468 return err;
2469 }
2470
Mattc7d4b2f2005-06-27 14:59:41 +02002471 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002472 err = create_controls(spec, chname[i], nid, 3);
2473 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002474 return err;
2475 }
2476 }
2477
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002478 if (cfg->hp_outs > 1) {
2479 err = stac92xx_add_control(spec,
2480 STAC_CTL_WIDGET_HP_SWITCH,
2481 "Headphone as Line Out Switch", 0);
2482 if (err < 0)
2483 return err;
2484 }
2485
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002486 if (spec->line_switch) {
2487 nid = cfg->input_pins[AUTO_PIN_LINE];
2488 pincap = snd_hda_param_read(codec, nid,
2489 AC_PAR_PIN_CAP);
2490 if (pincap & AC_PINCAP_OUT) {
2491 err = stac92xx_add_control(spec,
2492 STAC_CTL_WIDGET_IO_SWITCH,
2493 "Line In as Output Switch", nid << 8);
2494 if (err < 0)
2495 return err;
2496 }
2497 }
Matt Porter403d1942005-11-29 15:00:51 +01002498
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002499 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002500 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002501 unsigned int mic_pin = AUTO_PIN_MIC;
2502again:
2503 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002504 def_conf = snd_hda_codec_read(codec, nid, 0,
2505 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002506 /* some laptops have an internal analog microphone
2507 * which can't be used as a output */
2508 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2509 pincap = snd_hda_param_read(codec, nid,
2510 AC_PAR_PIN_CAP);
2511 if (pincap & AC_PINCAP_OUT) {
2512 err = stac92xx_add_control(spec,
2513 STAC_CTL_WIDGET_IO_SWITCH,
2514 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002515 nid = snd_hda_codec_read(codec, nid, 0,
2516 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2517 if (!check_in_dac_nids(spec, nid))
2518 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002519 if (err < 0)
2520 return err;
2521 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002522 } else if (mic_pin == AUTO_PIN_MIC) {
2523 mic_pin = AUTO_PIN_FRONT_MIC;
2524 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002525 }
2526 }
Matt Porter403d1942005-11-29 15:00:51 +01002527
Mattc7d4b2f2005-06-27 14:59:41 +02002528 return 0;
2529}
2530
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002531/* add playback controls for Speaker and HP outputs */
2532static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2533 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002534{
2535 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002536 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002537 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002538
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002539 old_num_dacs = spec->multiout.num_dacs;
2540 for (i = 0; i < cfg->hp_outs; i++) {
2541 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2542 if (wid_caps & AC_WCAP_UNSOL_CAP)
2543 spec->hp_detect = 1;
2544 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2545 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2546 if (check_in_dac_nids(spec, nid))
2547 nid = 0;
2548 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002549 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002550 add_spec_dacs(spec, nid);
2551 }
2552 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002553 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002554 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2555 if (check_in_dac_nids(spec, nid))
2556 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002557 if (! nid)
2558 continue;
2559 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002560 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002561 for (i = 0; i < cfg->line_outs; i++) {
2562 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2563 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2564 if (check_in_dac_nids(spec, nid))
2565 nid = 0;
2566 if (! nid)
2567 continue;
2568 add_spec_dacs(spec, nid);
2569 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002570 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2571 static const char *pfxs[] = {
2572 "Speaker", "External Speaker", "Speaker2",
2573 };
2574 err = create_controls(spec, pfxs[i - old_num_dacs],
2575 spec->multiout.dac_nids[i], 3);
2576 if (err < 0)
2577 return err;
2578 }
2579 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002580 err = create_controls(spec, "Headphone",
2581 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002582 if (err < 0)
2583 return err;
2584 }
Mattc7d4b2f2005-06-27 14:59:41 +02002585
2586 return 0;
2587}
2588
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002589/* labels for mono mux outputs */
2590static const char *stac92xx_mono_labels[3] = {
2591 "DAC0", "DAC1", "Mixer"
2592};
2593
2594/* create mono mux for mono out on capable codecs */
2595static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2596{
2597 struct sigmatel_spec *spec = codec->spec;
2598 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2599 int i, num_cons;
2600 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2601
2602 num_cons = snd_hda_get_connections(codec,
2603 spec->mono_nid,
2604 con_lst,
2605 HDA_MAX_NUM_INPUTS);
2606 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2607 return -EINVAL;
2608
2609 for (i = 0; i < num_cons; i++) {
2610 mono_mux->items[mono_mux->num_items].label =
2611 stac92xx_mono_labels[i];
2612 mono_mux->items[mono_mux->num_items].index = i;
2613 mono_mux->num_items++;
2614 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002615
2616 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2617 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002618}
2619
Matthew Ranostay1cd22242008-07-18 18:20:52 +02002620/* create PC beep volume controls */
2621static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
2622 hda_nid_t nid)
2623{
2624 struct sigmatel_spec *spec = codec->spec;
2625 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
2626 int err;
2627
2628 /* check for mute support for the the amp */
2629 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
2630 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2631 "PC Beep Playback Switch",
2632 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2633 if (err < 0)
2634 return err;
2635 }
2636
2637 /* check to see if there is volume support for the amp */
2638 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2639 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2640 "PC Beep Playback Volume",
2641 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
2642 if (err < 0)
2643 return err;
2644 }
2645 return 0;
2646}
2647
Matt Porter8b657272006-10-26 17:12:59 +02002648/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002649static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002650 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2651 "Digital Mic 3", "Digital Mic 4"
2652};
2653
2654/* create playback/capture controls for input pins on dmic capable codecs */
2655static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2656 const struct auto_pin_cfg *cfg)
2657{
2658 struct sigmatel_spec *spec = codec->spec;
2659 struct hda_input_mux *dimux = &spec->private_dimux;
2660 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002661 int err, i, j;
2662 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002663
2664 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2665 dimux->items[dimux->num_items].index = 0;
2666 dimux->num_items++;
2667
2668 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002669 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002670 int index;
2671 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002672 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002673 unsigned int def_conf;
2674
2675 def_conf = snd_hda_codec_read(codec,
2676 spec->dmic_nids[i],
2677 0,
2678 AC_VERB_GET_CONFIG_DEFAULT,
2679 0);
2680 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2681 continue;
2682
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002683 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002684 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002685 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002686 con_lst,
2687 HDA_MAX_NUM_INPUTS);
2688 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002689 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002690 index = j;
2691 goto found;
2692 }
2693 continue;
2694found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002695 wcaps = get_wcaps(codec, nid);
2696
2697 if (wcaps & AC_WCAP_OUT_AMP) {
2698 sprintf(name, "%s Capture Volume",
2699 stac92xx_dmic_labels[dimux->num_items]);
2700
2701 err = stac92xx_add_control(spec,
2702 STAC_CTL_WIDGET_VOL,
2703 name,
2704 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2705 if (err < 0)
2706 return err;
2707 }
2708
Matt Porter8b657272006-10-26 17:12:59 +02002709 dimux->items[dimux->num_items].label =
2710 stac92xx_dmic_labels[dimux->num_items];
2711 dimux->items[dimux->num_items].index = index;
2712 dimux->num_items++;
2713 }
2714
2715 return 0;
2716}
2717
Mattc7d4b2f2005-06-27 14:59:41 +02002718/* create playback/capture controls for input pins */
2719static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2720{
2721 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002722 struct hda_input_mux *imux = &spec->private_imux;
2723 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2724 int i, j, k;
2725
2726 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002727 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002728
Takashi Iwai314634b2006-09-21 11:56:18 +02002729 if (!cfg->input_pins[i])
2730 continue;
2731 index = -1;
2732 for (j = 0; j < spec->num_muxes; j++) {
2733 int num_cons;
2734 num_cons = snd_hda_get_connections(codec,
2735 spec->mux_nids[j],
2736 con_lst,
2737 HDA_MAX_NUM_INPUTS);
2738 for (k = 0; k < num_cons; k++)
2739 if (con_lst[k] == cfg->input_pins[i]) {
2740 index = k;
2741 goto found;
2742 }
Mattc7d4b2f2005-06-27 14:59:41 +02002743 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002744 continue;
2745 found:
2746 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2747 imux->items[imux->num_items].index = index;
2748 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002749 }
2750
Steve Longerbeam7b043892007-05-03 20:50:03 +02002751 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002752 /*
2753 * Set the current input for the muxes.
2754 * The STAC9221 has two input muxes with identical source
2755 * NID lists. Hopefully this won't get confused.
2756 */
2757 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002758 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2759 AC_VERB_SET_CONNECT_SEL,
2760 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002761 }
2762 }
2763
Mattc7d4b2f2005-06-27 14:59:41 +02002764 return 0;
2765}
2766
Mattc7d4b2f2005-06-27 14:59:41 +02002767static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2768{
2769 struct sigmatel_spec *spec = codec->spec;
2770 int i;
2771
2772 for (i = 0; i < spec->autocfg.line_outs; i++) {
2773 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2774 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2775 }
2776}
2777
2778static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2779{
2780 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002781 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002782
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002783 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2784 hda_nid_t pin;
2785 pin = spec->autocfg.hp_pins[i];
2786 if (pin) /* connect to front */
2787 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2788 }
2789 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2790 hda_nid_t pin;
2791 pin = spec->autocfg.speaker_pins[i];
2792 if (pin) /* connect to front */
2793 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2794 }
Mattc7d4b2f2005-06-27 14:59:41 +02002795}
2796
Matt Porter3cc08dc2006-01-23 15:27:49 +01002797static 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 +02002798{
2799 struct sigmatel_spec *spec = codec->spec;
2800 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002801 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002802
Matt Porter8b657272006-10-26 17:12:59 +02002803 if ((err = snd_hda_parse_pin_def_config(codec,
2804 &spec->autocfg,
2805 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002806 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002807 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002808 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002809
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002810 /* If we have no real line-out pin and multiple hp-outs, HPs should
2811 * be set up as multi-channel outputs.
2812 */
2813 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2814 spec->autocfg.hp_outs > 1) {
2815 /* Copy hp_outs to line_outs, backup line_outs in
2816 * speaker_outs so that the following routines can handle
2817 * HP pins as primary outputs.
2818 */
2819 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2820 sizeof(spec->autocfg.line_out_pins));
2821 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2822 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2823 sizeof(spec->autocfg.hp_pins));
2824 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2825 hp_speaker_swap = 1;
2826 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002827 if (spec->autocfg.mono_out_pin) {
2828 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2829 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2830 u32 caps = query_amp_caps(codec,
2831 spec->autocfg.mono_out_pin, dir);
2832 hda_nid_t conn_list[1];
2833
2834 /* get the mixer node and then the mono mux if it exists */
2835 if (snd_hda_get_connections(codec,
2836 spec->autocfg.mono_out_pin, conn_list, 1) &&
2837 snd_hda_get_connections(codec, conn_list[0],
2838 conn_list, 1)) {
2839
2840 int wcaps = get_wcaps(codec, conn_list[0]);
2841 int wid_type = (wcaps & AC_WCAP_TYPE)
2842 >> AC_WCAP_TYPE_SHIFT;
2843 /* LR swap check, some stac925x have a mux that
2844 * changes the DACs output path instead of the
2845 * mono-mux path.
2846 */
2847 if (wid_type == AC_WID_AUD_SEL &&
2848 !(wcaps & AC_WCAP_LR_SWAP))
2849 spec->mono_nid = conn_list[0];
2850 }
2851 /* all mono outs have a least a mute/unmute switch */
2852 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2853 "Mono Playback Switch",
2854 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2855 1, 0, dir));
2856 if (err < 0)
2857 return err;
2858 /* check to see if there is volume support for the amp */
2859 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2860 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2861 "Mono Playback Volume",
2862 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2863 1, 0, dir));
2864 if (err < 0)
2865 return err;
2866 }
2867
2868 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2869 AC_PINCTL_OUT_EN);
2870 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002871
Matt Porter403d1942005-11-29 15:00:51 +01002872 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2873 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002874 if (spec->multiout.num_dacs == 0)
2875 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2876 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002877
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002878 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2879
2880 if (err < 0)
2881 return err;
2882
Matthew Ranostay1cd22242008-07-18 18:20:52 +02002883 /* setup analog beep controls */
2884 if (spec->anabeep_nid > 0) {
2885 err = stac92xx_auto_create_beep_ctls(codec,
2886 spec->anabeep_nid);
2887 if (err < 0)
2888 return err;
2889 }
2890
2891 /* setup digital beep controls and input device */
2892#ifdef CONFIG_SND_HDA_INPUT_BEEP
2893 if (spec->digbeep_nid > 0) {
2894 hda_nid_t nid = spec->digbeep_nid;
2895
2896 err = stac92xx_auto_create_beep_ctls(codec, nid);
2897 if (err < 0)
2898 return err;
2899 err = snd_hda_attach_beep_device(codec, nid);
2900 if (err < 0)
2901 return err;
2902 }
2903#endif
2904
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002905 if (hp_speaker_swap == 1) {
2906 /* Restore the hp_outs and line_outs */
2907 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2908 sizeof(spec->autocfg.line_out_pins));
2909 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2910 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2911 sizeof(spec->autocfg.speaker_pins));
2912 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2913 memset(spec->autocfg.speaker_pins, 0,
2914 sizeof(spec->autocfg.speaker_pins));
2915 spec->autocfg.speaker_outs = 0;
2916 }
2917
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002918 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2919
2920 if (err < 0)
2921 return err;
2922
2923 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2924
2925 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002926 return err;
2927
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002928 if (spec->mono_nid > 0) {
2929 err = stac92xx_auto_create_mono_output_ctls(codec);
2930 if (err < 0)
2931 return err;
2932 }
2933
Matt Porter8b657272006-10-26 17:12:59 +02002934 if (spec->num_dmics > 0)
2935 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2936 &spec->autocfg)) < 0)
2937 return err;
2938
Mattc7d4b2f2005-06-27 14:59:41 +02002939 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002940 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002941 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002942
Takashi Iwai82bc9552006-03-21 11:24:42 +01002943 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002944 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002945 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002946 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002947
2948 if (spec->kctl_alloc)
2949 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2950
2951 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002952 if (!spec->dinput_mux)
2953 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002954 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002955
2956 return 1;
2957}
2958
Takashi Iwai82bc9552006-03-21 11:24:42 +01002959/* add playback controls for HP output */
2960static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2961 struct auto_pin_cfg *cfg)
2962{
2963 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002964 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002965 unsigned int wid_caps;
2966
2967 if (! pin)
2968 return 0;
2969
2970 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002971 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002972 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002973
2974 return 0;
2975}
2976
Richard Fish160ea0d2006-09-06 13:58:25 +02002977/* add playback controls for LFE output */
2978static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2979 struct auto_pin_cfg *cfg)
2980{
2981 struct sigmatel_spec *spec = codec->spec;
2982 int err;
2983 hda_nid_t lfe_pin = 0x0;
2984 int i;
2985
2986 /*
2987 * search speaker outs and line outs for a mono speaker pin
2988 * with an amp. If one is found, add LFE controls
2989 * for it.
2990 */
2991 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2992 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002993 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002994 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2995 if (wcaps == AC_WCAP_OUT_AMP)
2996 /* found a mono speaker with an amp, must be lfe */
2997 lfe_pin = pin;
2998 }
2999
3000 /* if speaker_outs is 0, then speakers may be in line_outs */
3001 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3002 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3003 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003004 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003005 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003006 AC_VERB_GET_CONFIG_DEFAULT,
3007 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003008 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003009 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003010 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3011 if (wcaps == AC_WCAP_OUT_AMP)
3012 /* found a mono speaker with an amp,
3013 must be lfe */
3014 lfe_pin = pin;
3015 }
3016 }
3017 }
3018
3019 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003020 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003021 if (err < 0)
3022 return err;
3023 }
3024
3025 return 0;
3026}
3027
Mattc7d4b2f2005-06-27 14:59:41 +02003028static int stac9200_parse_auto_config(struct hda_codec *codec)
3029{
3030 struct sigmatel_spec *spec = codec->spec;
3031 int err;
3032
Kailang Yangdf694da2005-12-05 19:42:22 +01003033 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003034 return err;
3035
3036 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3037 return err;
3038
Takashi Iwai82bc9552006-03-21 11:24:42 +01003039 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3040 return err;
3041
Richard Fish160ea0d2006-09-06 13:58:25 +02003042 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3043 return err;
3044
Takashi Iwai82bc9552006-03-21 11:24:42 +01003045 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003046 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003047 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003048 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003049
3050 if (spec->kctl_alloc)
3051 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3052
3053 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003054 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003055
3056 return 1;
3057}
3058
Sam Revitch62fe78e2006-05-10 15:09:17 +02003059/*
3060 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3061 * funky external mute control using GPIO pins.
3062 */
3063
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003064static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003065 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003066{
3067 unsigned int gpiostate, gpiomask, gpiodir;
3068
3069 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3070 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003071 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003072
3073 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3074 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003075 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003076
3077 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3078 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003079 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003080
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003081 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003082 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3083
3084 snd_hda_codec_write(codec, codec->afg, 0,
3085 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003086 snd_hda_codec_read(codec, codec->afg, 0,
3087 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003088
3089 msleep(1);
3090
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003091 snd_hda_codec_read(codec, codec->afg, 0,
3092 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003093}
3094
Takashi Iwai314634b2006-09-21 11:56:18 +02003095static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3096 unsigned int event)
3097{
3098 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003099 snd_hda_codec_write_cache(codec, nid, 0,
3100 AC_VERB_SET_UNSOLICITED_ENABLE,
3101 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003102}
3103
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003104static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3105{
3106 int i;
3107 for (i = 0; i < cfg->hp_outs; i++)
3108 if (cfg->hp_pins[i] == nid)
3109 return 1; /* nid is a HP-Out */
3110
3111 return 0; /* nid is not a HP-Out */
3112};
3113
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003114static void stac92xx_power_down(struct hda_codec *codec)
3115{
3116 struct sigmatel_spec *spec = codec->spec;
3117
3118 /* power down inactive DACs */
3119 hda_nid_t *dac;
3120 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003121 if (!is_in_dac_nids(spec, *dac) &&
3122 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003123 snd_hda_codec_write_cache(codec, *dac, 0,
3124 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3125}
3126
Mattc7d4b2f2005-06-27 14:59:41 +02003127static int stac92xx_init(struct hda_codec *codec)
3128{
3129 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003130 struct auto_pin_cfg *cfg = &spec->autocfg;
3131 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003132
Mattc7d4b2f2005-06-27 14:59:41 +02003133 snd_hda_sequence_write(codec, spec->init);
3134
Takashi Iwai82bc9552006-03-21 11:24:42 +01003135 /* set up pins */
3136 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003137 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003138 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003139 enable_pin_detect(codec, cfg->hp_pins[i],
3140 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003141 /* force to enable the first line-out; the others are set up
3142 * in unsol_event
3143 */
3144 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3145 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003146 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003147 /* fake event to set up pins */
3148 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3149 } else {
3150 stac92xx_auto_init_multi_out(codec);
3151 stac92xx_auto_init_hp_out(codec);
3152 }
3153 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003154 hda_nid_t nid = cfg->input_pins[i];
3155 if (nid) {
3156 unsigned int pinctl = AC_PINCTL_IN_EN;
3157 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3158 pinctl |= stac92xx_get_vref(codec, nid);
3159 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3160 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003161 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003162 for (i = 0; i < spec->num_dmics; i++)
3163 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3164 AC_PINCTL_IN_EN);
3165 for (i = 0; i < spec->num_pwrs; i++) {
3166 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3167 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3168 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3169 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003170 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3171 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003172 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003173 /* outputs are only ports capable of power management
3174 * any attempts on powering down a input port cause the
3175 * referenced VREF to act quirky.
3176 */
3177 if (pinctl & AC_PINCTL_IN_EN)
3178 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003179 /* skip any ports that don't have jacks since presence
3180 * detection is useless */
3181 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003182 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003183 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3184 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3185 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003186 if (spec->dac_list)
3187 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003188 if (cfg->dig_out_pin)
3189 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3190 AC_PINCTL_OUT_EN);
3191 if (cfg->dig_in_pin)
3192 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3193 AC_PINCTL_IN_EN);
3194
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003195 stac_gpio_set(codec, spec->gpio_mask,
3196 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003197
Mattc7d4b2f2005-06-27 14:59:41 +02003198 return 0;
3199}
3200
Matt2f2f4252005-04-13 14:45:30 +02003201static void stac92xx_free(struct hda_codec *codec)
3202{
Mattc7d4b2f2005-06-27 14:59:41 +02003203 struct sigmatel_spec *spec = codec->spec;
3204 int i;
3205
3206 if (! spec)
3207 return;
3208
3209 if (spec->kctl_alloc) {
3210 for (i = 0; i < spec->num_kctl_used; i++)
3211 kfree(spec->kctl_alloc[i].name);
3212 kfree(spec->kctl_alloc);
3213 }
3214
Richard Fish11b44bb2006-08-23 18:31:34 +02003215 if (spec->bios_pin_configs)
3216 kfree(spec->bios_pin_configs);
3217
Mattc7d4b2f2005-06-27 14:59:41 +02003218 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003219 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003220}
3221
Matt4e550962005-07-04 17:51:39 +02003222static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3223 unsigned int flag)
3224{
3225 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3226 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003227
Takashi Iwaif9acba42007-05-29 18:01:06 +02003228 if (pin_ctl & AC_PINCTL_IN_EN) {
3229 /*
3230 * we need to check the current set-up direction of
3231 * shared input pins since they can be switched via
3232 * "xxx as Output" mixer switch
3233 */
3234 struct sigmatel_spec *spec = codec->spec;
3235 struct auto_pin_cfg *cfg = &spec->autocfg;
3236 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3237 spec->line_switch) ||
3238 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3239 spec->mic_switch))
3240 return;
3241 }
3242
Steve Longerbeam7b043892007-05-03 20:50:03 +02003243 /* if setting pin direction bits, clear the current
3244 direction bits first */
3245 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3246 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3247
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003248 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003249 AC_VERB_SET_PIN_WIDGET_CONTROL,
3250 pin_ctl | flag);
3251}
3252
3253static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3254 unsigned int flag)
3255{
3256 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3257 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003258 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003259 AC_VERB_SET_PIN_WIDGET_CONTROL,
3260 pin_ctl & ~flag);
3261}
3262
Jiang Zhe40c1d302007-11-12 13:05:16 +01003263static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003264{
3265 if (!nid)
3266 return 0;
3267 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003268 & (1 << 31)) {
3269 unsigned int pinctl;
3270 pinctl = snd_hda_codec_read(codec, nid, 0,
3271 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3272 if (pinctl & AC_PINCTL_IN_EN)
3273 return 0; /* mic- or line-input */
3274 else
3275 return 1; /* HP-output */
3276 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003277 return 0;
3278}
3279
3280static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003281{
3282 struct sigmatel_spec *spec = codec->spec;
3283 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003284 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003285 int i, presence;
3286
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003287 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003288 if (spec->gpio_mute)
3289 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3290 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3291
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003292 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003293 if (presence)
3294 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003295 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3296 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003297 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003298 }
Matt4e550962005-07-04 17:51:39 +02003299
3300 if (presence) {
3301 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003302 if (spec->hp_switch)
3303 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003304 for (i = 0; i < cfg->line_outs; i++)
3305 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3306 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003307 for (i = 0; i < cfg->speaker_outs; i++)
3308 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3309 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003310 if (spec->eapd_mask)
3311 stac_gpio_set(codec, spec->gpio_mask,
3312 spec->gpio_dir, spec->gpio_data &
3313 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003314 } else {
3315 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003316 if (spec->hp_switch)
3317 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003318 for (i = 0; i < cfg->line_outs; i++)
3319 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3320 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003321 for (i = 0; i < cfg->speaker_outs; i++)
3322 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3323 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003324 if (spec->eapd_mask)
3325 stac_gpio_set(codec, spec->gpio_mask,
3326 spec->gpio_dir, spec->gpio_data |
3327 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003328 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003329 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3330 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003331}
3332
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003333static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3334{
3335 struct sigmatel_spec *spec = codec->spec;
3336 hda_nid_t nid = spec->pwr_nids[idx];
3337 int presence, val;
3338 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3339 & 0x000000ff;
3340 presence = get_hp_pin_presence(codec, nid);
3341 idx = 1 << idx;
3342
3343 if (presence)
3344 val &= ~idx;
3345 else
3346 val |= idx;
3347
3348 /* power down unused output ports */
3349 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3350};
3351
Takashi Iwai314634b2006-09-21 11:56:18 +02003352static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3353{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003354 struct sigmatel_spec *spec = codec->spec;
3355 int idx = res >> 26 & 0x0f;
3356
3357 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003358 case STAC_HP_EVENT:
3359 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003360 /* fallthru */
3361 case STAC_PWR_EVENT:
3362 if (spec->num_pwrs > 0)
3363 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003364 }
3365}
3366
Takashi Iwaicb53c622007-08-10 17:21:45 +02003367#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003368static int stac92xx_resume(struct hda_codec *codec)
3369{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003370 struct sigmatel_spec *spec = codec->spec;
3371
Richard Fish11b44bb2006-08-23 18:31:34 +02003372 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003373 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003374 stac_gpio_set(codec, spec->gpio_mask,
3375 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003376 snd_hda_codec_resume_amp(codec);
3377 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003378 /* power down inactive DACs */
3379 if (spec->dac_list)
3380 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003381 /* invoke unsolicited event to reset the HP state */
3382 if (spec->hp_detect)
3383 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003384 return 0;
3385}
3386#endif
3387
Matt2f2f4252005-04-13 14:45:30 +02003388static struct hda_codec_ops stac92xx_patch_ops = {
3389 .build_controls = stac92xx_build_controls,
3390 .build_pcms = stac92xx_build_pcms,
3391 .init = stac92xx_init,
3392 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003393 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003394#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003395 .resume = stac92xx_resume,
3396#endif
Matt2f2f4252005-04-13 14:45:30 +02003397};
3398
3399static int patch_stac9200(struct hda_codec *codec)
3400{
3401 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003402 int err;
Matt2f2f4252005-04-13 14:45:30 +02003403
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003404 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003405 if (spec == NULL)
3406 return -ENOMEM;
3407
3408 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003409 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003410 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003411 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3412 stac9200_models,
3413 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003414 if (spec->board_config < 0) {
3415 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3416 err = stac92xx_save_bios_config_regs(codec);
3417 if (err < 0) {
3418 stac92xx_free(codec);
3419 return err;
3420 }
3421 spec->pin_configs = spec->bios_pin_configs;
3422 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003423 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3424 stac92xx_set_config_regs(codec);
3425 }
Matt2f2f4252005-04-13 14:45:30 +02003426
3427 spec->multiout.max_channels = 2;
3428 spec->multiout.num_dacs = 1;
3429 spec->multiout.dac_nids = stac9200_dac_nids;
3430 spec->adc_nids = stac9200_adc_nids;
3431 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003432 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003433 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003434 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003435 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003436
Tobin Davisbf277782008-02-03 20:31:47 +01003437 if (spec->board_config == STAC_9200_GATEWAY ||
3438 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003439 spec->init = stac9200_eapd_init;
3440 else
3441 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003442 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003443
Takashi Iwai117f2572008-03-18 09:53:23 +01003444 if (spec->board_config == STAC_9200_PANASONIC) {
3445 spec->gpio_mask = spec->gpio_dir = 0x09;
3446 spec->gpio_data = 0x00;
3447 }
3448
Mattc7d4b2f2005-06-27 14:59:41 +02003449 err = stac9200_parse_auto_config(codec);
3450 if (err < 0) {
3451 stac92xx_free(codec);
3452 return err;
3453 }
Matt2f2f4252005-04-13 14:45:30 +02003454
3455 codec->patch_ops = stac92xx_patch_ops;
3456
3457 return 0;
3458}
3459
Tobin Davis8e21c342007-01-08 11:04:17 +01003460static int patch_stac925x(struct hda_codec *codec)
3461{
3462 struct sigmatel_spec *spec;
3463 int err;
3464
3465 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3466 if (spec == NULL)
3467 return -ENOMEM;
3468
3469 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003470 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003471 spec->pin_nids = stac925x_pin_nids;
3472 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3473 stac925x_models,
3474 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003475 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003476 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003477 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3478 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003479 err = stac92xx_save_bios_config_regs(codec);
3480 if (err < 0) {
3481 stac92xx_free(codec);
3482 return err;
3483 }
3484 spec->pin_configs = spec->bios_pin_configs;
3485 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3486 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3487 stac92xx_set_config_regs(codec);
3488 }
3489
3490 spec->multiout.max_channels = 2;
3491 spec->multiout.num_dacs = 1;
3492 spec->multiout.dac_nids = stac925x_dac_nids;
3493 spec->adc_nids = stac925x_adc_nids;
3494 spec->mux_nids = stac925x_mux_nids;
3495 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003496 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003497 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003498 switch (codec->vendor_id) {
3499 case 0x83847632: /* STAC9202 */
3500 case 0x83847633: /* STAC9202D */
3501 case 0x83847636: /* STAC9251 */
3502 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003503 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003504 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003505 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3506 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003507 break;
3508 default:
3509 spec->num_dmics = 0;
3510 break;
3511 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003512
3513 spec->init = stac925x_core_init;
3514 spec->mixer = stac925x_mixer;
3515
3516 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003517 if (!err) {
3518 if (spec->board_config < 0) {
3519 printk(KERN_WARNING "hda_codec: No auto-config is "
3520 "available, default to model=ref\n");
3521 spec->board_config = STAC_925x_REF;
3522 goto again;
3523 }
3524 err = -EINVAL;
3525 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003526 if (err < 0) {
3527 stac92xx_free(codec);
3528 return err;
3529 }
3530
3531 codec->patch_ops = stac92xx_patch_ops;
3532
3533 return 0;
3534}
3535
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003536static struct hda_input_mux stac92hd73xx_dmux = {
3537 .num_items = 4,
3538 .items = {
3539 { "Analog Inputs", 0x0b },
3540 { "CD", 0x08 },
3541 { "Digital Mic 1", 0x09 },
3542 { "Digital Mic 2", 0x0a },
3543 }
3544};
3545
3546static int patch_stac92hd73xx(struct hda_codec *codec)
3547{
3548 struct sigmatel_spec *spec;
3549 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3550 int err = 0;
3551
3552 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3553 if (spec == NULL)
3554 return -ENOMEM;
3555
3556 codec->spec = spec;
3557 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3558 spec->pin_nids = stac92hd73xx_pin_nids;
3559 spec->board_config = snd_hda_check_board_config(codec,
3560 STAC_92HD73XX_MODELS,
3561 stac92hd73xx_models,
3562 stac92hd73xx_cfg_tbl);
3563again:
3564 if (spec->board_config < 0) {
3565 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3566 " STAC92HD73XX, using BIOS defaults\n");
3567 err = stac92xx_save_bios_config_regs(codec);
3568 if (err < 0) {
3569 stac92xx_free(codec);
3570 return err;
3571 }
3572 spec->pin_configs = spec->bios_pin_configs;
3573 } else {
3574 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3575 stac92xx_set_config_regs(codec);
3576 }
3577
3578 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3579 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3580
3581 if (spec->multiout.num_dacs < 0) {
3582 printk(KERN_WARNING "hda_codec: Could not determine "
3583 "number of channels defaulting to DAC count\n");
3584 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3585 }
3586
3587 switch (spec->multiout.num_dacs) {
3588 case 0x3: /* 6 Channel */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003589 spec->multiout.hp_nid = 0x17;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003590 spec->mixer = stac92hd73xx_6ch_mixer;
3591 spec->init = stac92hd73xx_6ch_core_init;
3592 break;
3593 case 0x4: /* 8 Channel */
3594 spec->multiout.hp_nid = 0x18;
3595 spec->mixer = stac92hd73xx_8ch_mixer;
3596 spec->init = stac92hd73xx_8ch_core_init;
3597 break;
3598 case 0x5: /* 10 Channel */
3599 spec->multiout.hp_nid = 0x19;
3600 spec->mixer = stac92hd73xx_10ch_mixer;
3601 spec->init = stac92hd73xx_10ch_core_init;
3602 };
3603
3604 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3605 spec->aloopback_mask = 0x01;
3606 spec->aloopback_shift = 8;
3607
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003608 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003609 spec->mux_nids = stac92hd73xx_mux_nids;
3610 spec->adc_nids = stac92hd73xx_adc_nids;
3611 spec->dmic_nids = stac92hd73xx_dmic_nids;
3612 spec->dmux_nids = stac92hd73xx_dmux_nids;
3613
3614 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3615 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003616 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003617 spec->dinput_mux = &stac92hd73xx_dmux;
3618 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003619 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003620 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003621
Matthew Ranostaya7662642008-02-21 07:51:14 +01003622 switch (spec->board_config) {
3623 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003624 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003625 switch (codec->subsystem_id) {
3626 case 0x1028025e: /* Analog Mics */
3627 case 0x1028025f:
3628 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3629 spec->num_dmics = 0;
3630 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003631 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003632 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003633 spec->init = dell_m6_core_init;
3634 /* fall-through */
3635 case 0x10280254:
3636 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003637 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3638 spec->num_dmics = 1;
3639 break;
3640 case 0x10280256: /* Both */
3641 case 0x10280057:
3642 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3643 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3644 spec->num_dmics = 1;
3645 break;
3646 }
3647 break;
3648 default:
3649 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3650 }
3651
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003652 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3653 spec->pwr_nids = stac92hd73xx_pwr_nids;
3654
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003655 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3656
3657 if (!err) {
3658 if (spec->board_config < 0) {
3659 printk(KERN_WARNING "hda_codec: No auto-config is "
3660 "available, default to model=ref\n");
3661 spec->board_config = STAC_92HD73XX_REF;
3662 goto again;
3663 }
3664 err = -EINVAL;
3665 }
3666
3667 if (err < 0) {
3668 stac92xx_free(codec);
3669 return err;
3670 }
3671
3672 codec->patch_ops = stac92xx_patch_ops;
3673
3674 return 0;
3675}
3676
Matthew Ranostaye035b842007-11-06 11:53:55 +01003677static int patch_stac92hd71bxx(struct hda_codec *codec)
3678{
3679 struct sigmatel_spec *spec;
3680 int err = 0;
3681
3682 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3683 if (spec == NULL)
3684 return -ENOMEM;
3685
3686 codec->spec = spec;
3687 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003688 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003689 spec->pin_nids = stac92hd71bxx_pin_nids;
3690 spec->board_config = snd_hda_check_board_config(codec,
3691 STAC_92HD71BXX_MODELS,
3692 stac92hd71bxx_models,
3693 stac92hd71bxx_cfg_tbl);
3694again:
3695 if (spec->board_config < 0) {
3696 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3697 " STAC92HD71BXX, using BIOS defaults\n");
3698 err = stac92xx_save_bios_config_regs(codec);
3699 if (err < 0) {
3700 stac92xx_free(codec);
3701 return err;
3702 }
3703 spec->pin_configs = spec->bios_pin_configs;
3704 } else {
3705 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3706 stac92xx_set_config_regs(codec);
3707 }
3708
Matthew Ranostay541eee82007-12-14 12:08:04 +01003709 switch (codec->vendor_id) {
3710 case 0x111d76b6: /* 4 Port without Analog Mixer */
3711 case 0x111d76b7:
3712 case 0x111d76b4: /* 6 Port without Analog Mixer */
3713 case 0x111d76b5:
3714 spec->mixer = stac92hd71bxx_mixer;
3715 spec->init = stac92hd71bxx_core_init;
3716 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003717 case 0x111d7608: /* 5 Port with Analog Mixer */
3718 /* no output amps */
3719 spec->num_pwrs = 0;
3720 spec->mixer = stac92hd71bxx_analog_mixer;
3721
3722 /* disable VSW */
3723 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
3724 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
3725 break;
3726 case 0x111d7603: /* 6 Port with Analog Mixer */
3727 /* no output amps */
3728 spec->num_pwrs = 0;
3729 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01003730 default:
3731 spec->mixer = stac92hd71bxx_analog_mixer;
3732 spec->init = stac92hd71bxx_analog_core_init;
3733 }
3734
3735 spec->aloopback_mask = 0x20;
3736 spec->aloopback_shift = 0;
3737
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003738 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003739 spec->gpio_mask = 0x01;
3740 spec->gpio_dir = 0x01;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003741 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003742
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003743 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003744 spec->mux_nids = stac92hd71bxx_mux_nids;
3745 spec->adc_nids = stac92hd71bxx_adc_nids;
3746 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003747 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003748 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003749
3750 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3751 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3752 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003753 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003754
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01003755 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003756 spec->multiout.hp_nid = 0x11;
3757 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3758
3759 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3760 if (!err) {
3761 if (spec->board_config < 0) {
3762 printk(KERN_WARNING "hda_codec: No auto-config is "
3763 "available, default to model=ref\n");
3764 spec->board_config = STAC_92HD71BXX_REF;
3765 goto again;
3766 }
3767 err = -EINVAL;
3768 }
3769
3770 if (err < 0) {
3771 stac92xx_free(codec);
3772 return err;
3773 }
3774
3775 codec->patch_ops = stac92xx_patch_ops;
3776
3777 return 0;
3778};
3779
Matt2f2f4252005-04-13 14:45:30 +02003780static int patch_stac922x(struct hda_codec *codec)
3781{
3782 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003783 int err;
Matt2f2f4252005-04-13 14:45:30 +02003784
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003785 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003786 if (spec == NULL)
3787 return -ENOMEM;
3788
3789 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003790 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003791 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003792 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3793 stac922x_models,
3794 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08003795 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003796 spec->gpio_mask = spec->gpio_dir = 0x03;
3797 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003798 /* Intel Macs have all same PCI SSID, so we need to check
3799 * codec SSID to distinguish the exact models
3800 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003801 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003802 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003803
3804 case 0x106b0800:
3805 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003806 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003807 case 0x106b0600:
3808 case 0x106b0700:
3809 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003810 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003811 case 0x106b0e00:
3812 case 0x106b0f00:
3813 case 0x106b1600:
3814 case 0x106b1700:
3815 case 0x106b0200:
3816 case 0x106b1e00:
3817 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003818 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003819 case 0x106b1a00:
3820 case 0x00000100:
3821 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003822 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003823 case 0x106b0a00:
3824 case 0x106b2200:
3825 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003826 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08003827 default:
3828 spec->board_config = STAC_INTEL_MAC_V3;
3829 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003830 }
3831 }
3832
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003833 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003834 if (spec->board_config < 0) {
3835 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3836 "using BIOS defaults\n");
3837 err = stac92xx_save_bios_config_regs(codec);
3838 if (err < 0) {
3839 stac92xx_free(codec);
3840 return err;
3841 }
3842 spec->pin_configs = spec->bios_pin_configs;
3843 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003844 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3845 stac92xx_set_config_regs(codec);
3846 }
Matt2f2f4252005-04-13 14:45:30 +02003847
Matt2f2f4252005-04-13 14:45:30 +02003848 spec->adc_nids = stac922x_adc_nids;
3849 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003850 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003851 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003852 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003853 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003854
3855 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003856 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003857
3858 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003859
Matt Porter3cc08dc2006-01-23 15:27:49 +01003860 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003861 if (!err) {
3862 if (spec->board_config < 0) {
3863 printk(KERN_WARNING "hda_codec: No auto-config is "
3864 "available, default to model=ref\n");
3865 spec->board_config = STAC_D945_REF;
3866 goto again;
3867 }
3868 err = -EINVAL;
3869 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003870 if (err < 0) {
3871 stac92xx_free(codec);
3872 return err;
3873 }
3874
3875 codec->patch_ops = stac92xx_patch_ops;
3876
Takashi Iwai807a46362007-05-29 19:01:37 +02003877 /* Fix Mux capture level; max to 2 */
3878 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3879 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3880 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3881 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3882 (0 << AC_AMPCAP_MUTE_SHIFT));
3883
Matt Porter3cc08dc2006-01-23 15:27:49 +01003884 return 0;
3885}
3886
3887static int patch_stac927x(struct hda_codec *codec)
3888{
3889 struct sigmatel_spec *spec;
3890 int err;
3891
3892 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3893 if (spec == NULL)
3894 return -ENOMEM;
3895
3896 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003897 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003898 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003899 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3900 stac927x_models,
3901 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003902 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003903 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3904 if (spec->board_config < 0)
3905 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3906 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003907 err = stac92xx_save_bios_config_regs(codec);
3908 if (err < 0) {
3909 stac92xx_free(codec);
3910 return err;
3911 }
3912 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003913 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003914 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3915 stac92xx_set_config_regs(codec);
3916 }
3917
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003918 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003919 spec->adc_nids = stac927x_adc_nids;
3920 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3921 spec->mux_nids = stac927x_mux_nids;
3922 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003923 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003924 spec->multiout.dac_nids = spec->dac_nids;
3925
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003926 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003927 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003928 case STAC_D965_5ST:
3929 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003930 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003931 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003932 spec->num_dmics = 0;
3933
Tobin Davis93ed1502006-09-01 21:03:12 +02003934 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003935 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003936 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003937 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02003938 switch (codec->subsystem_id) {
3939 case 0x10280209:
3940 case 0x1028022e:
3941 /* correct the device field to SPDIF out */
3942 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
3943 break;
3944 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003945 /* configure the analog microphone on some laptops */
3946 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003947 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003948 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003949 /* correct the front input jack as a mic */
3950 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3951 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003952 case STAC_DELL_3ST:
3953 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003954 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003955 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003956 spec->dmic_nids = stac927x_dmic_nids;
3957 spec->num_dmics = STAC927X_NUM_DMICS;
3958
Tobin Davis93ed1502006-09-01 21:03:12 +02003959 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003960 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003961 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003962 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003963 break;
3964 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003965 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003966 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003967 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003968 spec->num_dmics = 0;
3969
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003970 spec->init = stac927x_core_init;
3971 spec->mixer = stac927x_mixer;
3972 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003973
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003974 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003975 spec->aloopback_mask = 0x40;
3976 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003977
Matt Porter3cc08dc2006-01-23 15:27:49 +01003978 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003979 if (!err) {
3980 if (spec->board_config < 0) {
3981 printk(KERN_WARNING "hda_codec: No auto-config is "
3982 "available, default to model=ref\n");
3983 spec->board_config = STAC_D965_REF;
3984 goto again;
3985 }
3986 err = -EINVAL;
3987 }
Mattc7d4b2f2005-06-27 14:59:41 +02003988 if (err < 0) {
3989 stac92xx_free(codec);
3990 return err;
3991 }
Matt2f2f4252005-04-13 14:45:30 +02003992
3993 codec->patch_ops = stac92xx_patch_ops;
3994
Takashi Iwai52987652008-01-16 16:09:47 +01003995 /*
3996 * !!FIXME!!
3997 * The STAC927x seem to require fairly long delays for certain
3998 * command sequences. With too short delays (even if the answer
3999 * is set to RIRB properly), it results in the silence output
4000 * on some hardwares like Dell.
4001 *
4002 * The below flag enables the longer delay (see get_response
4003 * in hda_intel.c).
4004 */
4005 codec->bus->needs_damn_long_delay = 1;
4006
Matt2f2f4252005-04-13 14:45:30 +02004007 return 0;
4008}
4009
Matt Porterf3302a52006-07-31 12:49:34 +02004010static int patch_stac9205(struct hda_codec *codec)
4011{
4012 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004013 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004014
4015 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4016 if (spec == NULL)
4017 return -ENOMEM;
4018
4019 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004020 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004021 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004022 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4023 stac9205_models,
4024 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004025 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004026 if (spec->board_config < 0) {
4027 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4028 err = stac92xx_save_bios_config_regs(codec);
4029 if (err < 0) {
4030 stac92xx_free(codec);
4031 return err;
4032 }
4033 spec->pin_configs = spec->bios_pin_configs;
4034 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004035 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4036 stac92xx_set_config_regs(codec);
4037 }
4038
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004039 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004040 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004041 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004042 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004043 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004044 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004045 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004046 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004047 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004048 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004049
4050 spec->init = stac9205_core_init;
4051 spec->mixer = stac9205_mixer;
4052
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004053 spec->aloopback_mask = 0x40;
4054 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004055 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004056
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004057 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004058 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004059 /* Enable SPDIF in/out */
4060 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4061 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004062
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004063 /* Enable unsol response for GPIO4/Dock HP connection */
4064 snd_hda_codec_write(codec, codec->afg, 0,
4065 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4066 snd_hda_codec_write_cache(codec, codec->afg, 0,
4067 AC_VERB_SET_UNSOLICITED_ENABLE,
4068 (AC_USRSP_EN | STAC_HP_EVENT));
4069
4070 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004071 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004072 spec->gpio_mask = 0x1b;
4073 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004074 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004075 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004076 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004077 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004078 break;
4079 default:
4080 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004081 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004082 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004083 break;
4084 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004085
Matt Porterf3302a52006-07-31 12:49:34 +02004086 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004087 if (!err) {
4088 if (spec->board_config < 0) {
4089 printk(KERN_WARNING "hda_codec: No auto-config is "
4090 "available, default to model=ref\n");
4091 spec->board_config = STAC_9205_REF;
4092 goto again;
4093 }
4094 err = -EINVAL;
4095 }
Matt Porterf3302a52006-07-31 12:49:34 +02004096 if (err < 0) {
4097 stac92xx_free(codec);
4098 return err;
4099 }
4100
4101 codec->patch_ops = stac92xx_patch_ops;
4102
4103 return 0;
4104}
4105
Matt2f2f4252005-04-13 14:45:30 +02004106/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004107 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004108 */
4109
Guillaume Munch99ccc562006-08-16 19:35:12 +02004110/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004111static hda_nid_t vaio_dacs[] = { 0x2 };
4112#define VAIO_HP_DAC 0x5
4113static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4114static hda_nid_t vaio_mux_nids[] = { 0x15 };
4115
4116static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004117 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004118 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004119 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004120 { "Mic Jack", 0x1 },
4121 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004122 { "PCM", 0x3 },
4123 }
4124};
4125
4126static struct hda_verb vaio_init[] = {
4127 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004128 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004129 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4130 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4131 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4132 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004133 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004134 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4135 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4136 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4137 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4138 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4139 {}
4140};
4141
Guillaume Munch6d859062006-08-22 17:15:47 +02004142static struct hda_verb vaio_ar_init[] = {
4143 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4144 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4145 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4146 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4147/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4148 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004149 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004150 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4151 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4152/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4153 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4154 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4155 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4156 {}
4157};
4158
Takashi Iwaidb064e52006-03-16 16:04:58 +01004159/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004160static struct hda_bind_ctls vaio_bind_master_vol = {
4161 .ops = &snd_hda_bind_vol,
4162 .values = {
4163 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4164 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4165 0
4166 },
4167};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004168
4169/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004170static struct hda_bind_ctls vaio_bind_master_sw = {
4171 .ops = &snd_hda_bind_sw,
4172 .values = {
4173 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4174 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4175 0,
4176 },
4177};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004178
4179static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004180 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4181 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004182 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4183 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4184 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4185 {
4186 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4187 .name = "Capture Source",
4188 .count = 1,
4189 .info = stac92xx_mux_enum_info,
4190 .get = stac92xx_mux_enum_get,
4191 .put = stac92xx_mux_enum_put,
4192 },
4193 {}
4194};
4195
Guillaume Munch6d859062006-08-22 17:15:47 +02004196static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004197 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4198 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004199 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4200 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4201 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4202 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4203 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4204 {
4205 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4206 .name = "Capture Source",
4207 .count = 1,
4208 .info = stac92xx_mux_enum_info,
4209 .get = stac92xx_mux_enum_get,
4210 .put = stac92xx_mux_enum_put,
4211 },
4212 {}
4213};
4214
4215static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004216 .build_controls = stac92xx_build_controls,
4217 .build_pcms = stac92xx_build_pcms,
4218 .init = stac92xx_init,
4219 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004220#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004221 .resume = stac92xx_resume,
4222#endif
4223};
4224
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004225static int stac9872_vaio_init(struct hda_codec *codec)
4226{
4227 int err;
4228
4229 err = stac92xx_init(codec);
4230 if (err < 0)
4231 return err;
4232 if (codec->patch_ops.unsol_event)
4233 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4234 return 0;
4235}
4236
4237static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4238{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004239 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004240 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4241 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4242 } else {
4243 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4244 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4245 }
4246}
4247
4248static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4249{
4250 switch (res >> 26) {
4251 case STAC_HP_EVENT:
4252 stac9872_vaio_hp_detect(codec, res);
4253 break;
4254 }
4255}
4256
4257static struct hda_codec_ops stac9872_vaio_patch_ops = {
4258 .build_controls = stac92xx_build_controls,
4259 .build_pcms = stac92xx_build_pcms,
4260 .init = stac9872_vaio_init,
4261 .free = stac92xx_free,
4262 .unsol_event = stac9872_vaio_unsol_event,
4263#ifdef CONFIG_PM
4264 .resume = stac92xx_resume,
4265#endif
4266};
4267
Guillaume Munch6d859062006-08-22 17:15:47 +02004268enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4269 CXD9872RD_VAIO,
4270 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4271 STAC9872AK_VAIO,
4272 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4273 STAC9872K_VAIO,
4274 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004275 CXD9872AKD_VAIO,
4276 STAC_9872_MODELS,
4277};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004278
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004279static const char *stac9872_models[STAC_9872_MODELS] = {
4280 [CXD9872RD_VAIO] = "vaio",
4281 [CXD9872AKD_VAIO] = "vaio-ar",
4282};
4283
4284static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4285 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4286 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4287 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004288 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004289 {}
4290};
4291
Guillaume Munch6d859062006-08-22 17:15:47 +02004292static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004293{
4294 struct sigmatel_spec *spec;
4295 int board_config;
4296
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004297 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4298 stac9872_models,
4299 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004300 if (board_config < 0)
4301 /* unknown config, let generic-parser do its job... */
4302 return snd_hda_parse_generic_codec(codec);
4303
4304 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4305 if (spec == NULL)
4306 return -ENOMEM;
4307
4308 codec->spec = spec;
4309 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004310 case CXD9872RD_VAIO:
4311 case STAC9872AK_VAIO:
4312 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004313 spec->mixer = vaio_mixer;
4314 spec->init = vaio_init;
4315 spec->multiout.max_channels = 2;
4316 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4317 spec->multiout.dac_nids = vaio_dacs;
4318 spec->multiout.hp_nid = VAIO_HP_DAC;
4319 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4320 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004321 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004322 spec->input_mux = &vaio_mux;
4323 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004324 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004325 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004326
4327 case CXD9872AKD_VAIO:
4328 spec->mixer = vaio_ar_mixer;
4329 spec->init = vaio_ar_init;
4330 spec->multiout.max_channels = 2;
4331 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4332 spec->multiout.dac_nids = vaio_dacs;
4333 spec->multiout.hp_nid = VAIO_HP_DAC;
4334 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004335 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004336 spec->adc_nids = vaio_adcs;
4337 spec->input_mux = &vaio_mux;
4338 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004339 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004340 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004341 }
4342
Takashi Iwaidb064e52006-03-16 16:04:58 +01004343 return 0;
4344}
4345
4346
4347/*
Matt2f2f4252005-04-13 14:45:30 +02004348 * patch entries
4349 */
4350struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4351 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4352 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4353 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4354 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4355 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4356 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4357 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004358 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4359 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4360 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4361 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4362 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4363 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004364 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4365 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4366 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4367 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4368 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4369 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4370 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4371 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4372 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4373 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004374 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4375 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4376 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4377 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4378 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4379 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02004380 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
4381 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004382 /* The following does not take into account .id=0x83847661 when subsys =
4383 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4384 * currently not fully supported.
4385 */
4386 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4387 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4388 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004389 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4390 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4391 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4392 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4393 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4394 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4395 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4396 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004397 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
4398 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01004399 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4400 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004401 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004402 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4403 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4404 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4405 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4406 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4407 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4408 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4409 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004410 {} /* terminator */
4411};