blob: e1d07ab5cd153edb754e613a1845831b6edfc0a4 [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010035#include "hda_patch.h"
Matt2f2f4252005-04-13 14:45:30 +020036
Matt4e550962005-07-04 17:51:39 +020037#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010038#define STAC_PWR_EVENT 0x20
39#define STAC_HP_EVENT 0x30
Matt4e550962005-07-04 17:51:39 +020040
Takashi Iwaif5fcc132006-11-24 17:07:44 +010041enum {
42 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010043 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020044 STAC_9200_DELL_D21,
45 STAC_9200_DELL_D22,
46 STAC_9200_DELL_D23,
47 STAC_9200_DELL_M21,
48 STAC_9200_DELL_M22,
49 STAC_9200_DELL_M23,
50 STAC_9200_DELL_M24,
51 STAC_9200_DELL_M25,
52 STAC_9200_DELL_M26,
53 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020054 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010055 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010056 STAC_9200_MODELS
57};
58
59enum {
60 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020061 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020062 STAC_9205_DELL_M43,
63 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010064 STAC_9205_MODELS
65};
66
67enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010068 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010069 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010070 STAC_92HD73XX_MODELS
71};
72
73enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010074 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010075 STAC_DELL_M4_1,
76 STAC_DELL_M4_2,
Matthew Ranostaye035b842007-11-06 11:53:55 +010077 STAC_92HD71BXX_MODELS
78};
79
80enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010081 STAC_925x_REF,
82 STAC_M2_2,
83 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020084 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010085 STAC_925x_MODELS
86};
87
88enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010089 STAC_D945_REF,
90 STAC_D945GTP3,
91 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +020092 STAC_INTEL_MAC_V1,
93 STAC_INTEL_MAC_V2,
94 STAC_INTEL_MAC_V3,
95 STAC_INTEL_MAC_V4,
96 STAC_INTEL_MAC_V5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020097 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010098 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +010099 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100100 STAC_MACBOOK_PRO_V1,
101 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200102 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200103 STAC_IMAC_INTEL_20,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200104 STAC_922X_DELL_D81,
105 STAC_922X_DELL_D82,
106 STAC_922X_DELL_M81,
107 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100108 STAC_922X_MODELS
109};
110
111enum {
112 STAC_D965_REF,
113 STAC_D965_3ST,
114 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200115 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100116 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100117 STAC_927X_MODELS
118};
Matt Porter403d1942005-11-29 15:00:51 +0100119
Matt2f2f4252005-04-13 14:45:30 +0200120struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100121 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200122 unsigned int num_mixers;
123
Matt Porter403d1942005-11-29 15:00:51 +0100124 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200125 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100126 unsigned int line_switch: 1;
127 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100128 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100129 unsigned int hp_detect: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200130
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100131 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200132 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100133 unsigned int gpio_mask;
134 unsigned int gpio_dir;
135 unsigned int gpio_data;
136 unsigned int gpio_mute;
137
138 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100139 unsigned char aloopback_mask;
140 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200141
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100142 /* power management */
143 unsigned int num_pwrs;
144 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100145 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100146
Matt2f2f4252005-04-13 14:45:30 +0200147 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100148 struct hda_input_mux *mono_mux;
149 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200150 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100151 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200152
153 /* capture */
154 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200155 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200156 hda_nid_t *mux_nids;
157 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200158 hda_nid_t *dmic_nids;
159 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100160 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100161 unsigned int num_dmuxes;
Mattdabbed62005-06-14 10:19:34 +0200162 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100163 hda_nid_t mono_nid;
Matt2f2f4252005-04-13 14:45:30 +0200164
Matt2f2f4252005-04-13 14:45:30 +0200165 /* pin widgets */
166 hda_nid_t *pin_nids;
167 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200168 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200169 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200170
171 /* codec specific stuff */
172 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100173 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200174
175 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200176 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100177 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200178 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100179 unsigned int cur_mux[3];
Matt2f2f4252005-04-13 14:45:30 +0200180
Matt Porter403d1942005-11-29 15:00:51 +0100181 /* i/o switches */
182 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200183 unsigned int clfe_swap;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200184 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200185
Mattc7d4b2f2005-06-27 14:59:41 +0200186 struct hda_pcm pcm_rec[2]; /* PCM information */
187
188 /* dynamic controls and input_mux */
189 struct auto_pin_cfg autocfg;
190 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100191 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200192 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200193 struct hda_input_mux private_imux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100194 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200195};
196
197static hda_nid_t stac9200_adc_nids[1] = {
198 0x03,
199};
200
201static hda_nid_t stac9200_mux_nids[1] = {
202 0x0c,
203};
204
205static hda_nid_t stac9200_dac_nids[1] = {
206 0x02,
207};
208
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100209static hda_nid_t stac92hd73xx_pwr_nids[8] = {
210 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
211 0x0f, 0x10, 0x11
212};
213
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100214static hda_nid_t stac92hd73xx_adc_nids[2] = {
215 0x1a, 0x1b
216};
217
218#define STAC92HD73XX_NUM_DMICS 2
219static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
220 0x13, 0x14, 0
221};
222
223#define STAC92HD73_DAC_COUNT 5
224static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
225 0x15, 0x16, 0x17, 0x18, 0x19,
226};
227
228static hda_nid_t stac92hd73xx_mux_nids[4] = {
229 0x28, 0x29, 0x2a, 0x2b,
230};
231
232static hda_nid_t stac92hd73xx_dmux_nids[2] = {
233 0x20, 0x21,
234};
235
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100236static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
237 0x0a, 0x0d, 0x0f
238};
239
Matthew Ranostaye035b842007-11-06 11:53:55 +0100240static hda_nid_t stac92hd71bxx_adc_nids[2] = {
241 0x12, 0x13,
242};
243
244static hda_nid_t stac92hd71bxx_mux_nids[2] = {
245 0x1a, 0x1b
246};
247
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100248static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
249 0x1c,
250};
251
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100252static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100253 0x10, /*0x11, */
254};
255
256#define STAC92HD71BXX_NUM_DMICS 2
257static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
258 0x18, 0x19, 0
259};
260
Tobin Davis8e21c342007-01-08 11:04:17 +0100261static hda_nid_t stac925x_adc_nids[1] = {
262 0x03,
263};
264
265static hda_nid_t stac925x_mux_nids[1] = {
266 0x0f,
267};
268
269static hda_nid_t stac925x_dac_nids[1] = {
270 0x02,
271};
272
Takashi Iwaif6e98522007-10-16 14:27:04 +0200273#define STAC925X_NUM_DMICS 1
274static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
275 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200276};
277
Takashi Iwai1697055e2007-12-18 18:05:52 +0100278static hda_nid_t stac925x_dmux_nids[1] = {
279 0x14,
280};
281
Matt2f2f4252005-04-13 14:45:30 +0200282static hda_nid_t stac922x_adc_nids[2] = {
283 0x06, 0x07,
284};
285
286static hda_nid_t stac922x_mux_nids[2] = {
287 0x12, 0x13,
288};
289
Matt Porter3cc08dc2006-01-23 15:27:49 +0100290static hda_nid_t stac927x_adc_nids[3] = {
291 0x07, 0x08, 0x09
292};
293
294static hda_nid_t stac927x_mux_nids[3] = {
295 0x15, 0x16, 0x17
296};
297
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100298static hda_nid_t stac927x_dac_nids[6] = {
299 0x02, 0x03, 0x04, 0x05, 0x06, 0
300};
301
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100302static hda_nid_t stac927x_dmux_nids[1] = {
303 0x1b,
304};
305
Matthew Ranostay7f168592007-10-18 17:38:17 +0200306#define STAC927X_NUM_DMICS 2
307static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
308 0x13, 0x14, 0
309};
310
Matt Porterf3302a52006-07-31 12:49:34 +0200311static hda_nid_t stac9205_adc_nids[2] = {
312 0x12, 0x13
313};
314
315static hda_nid_t stac9205_mux_nids[2] = {
316 0x19, 0x1a
317};
318
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100319static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100320 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100321};
322
Takashi Iwaif6e98522007-10-16 14:27:04 +0200323#define STAC9205_NUM_DMICS 2
324static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
325 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200326};
327
Mattc7d4b2f2005-06-27 14:59:41 +0200328static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200329 0x08, 0x09, 0x0d, 0x0e,
330 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200331};
332
Tobin Davis8e21c342007-01-08 11:04:17 +0100333static hda_nid_t stac925x_pin_nids[8] = {
334 0x07, 0x08, 0x0a, 0x0b,
335 0x0c, 0x0d, 0x10, 0x11,
336};
337
Matt2f2f4252005-04-13 14:45:30 +0200338static hda_nid_t stac922x_pin_nids[10] = {
339 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
340 0x0f, 0x10, 0x11, 0x15, 0x1b,
341};
342
Matthew Ranostaya7662642008-02-21 07:51:14 +0100343static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100344 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
345 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100346 0x14, 0x1e, 0x22
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100347};
348
Matthew Ranostaye035b842007-11-06 11:53:55 +0100349static hda_nid_t stac92hd71bxx_pin_nids[10] = {
350 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
351 0x0f, 0x14, 0x18, 0x19, 0x1e,
352};
353
Matt Porter3cc08dc2006-01-23 15:27:49 +0100354static hda_nid_t stac927x_pin_nids[14] = {
355 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
356 0x0f, 0x10, 0x11, 0x12, 0x13,
357 0x14, 0x21, 0x22, 0x23,
358};
359
Matt Porterf3302a52006-07-31 12:49:34 +0200360static hda_nid_t stac9205_pin_nids[12] = {
361 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
362 0x0f, 0x14, 0x16, 0x17, 0x18,
363 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200364};
365
Matt Porter8b657272006-10-26 17:12:59 +0200366static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
367 struct snd_ctl_elem_info *uinfo)
368{
369 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
370 struct sigmatel_spec *spec = codec->spec;
371 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
372}
373
374static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
375 struct snd_ctl_elem_value *ucontrol)
376{
377 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
378 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100379 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200380
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100381 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200382 return 0;
383}
384
385static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
386 struct snd_ctl_elem_value *ucontrol)
387{
388 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
389 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100390 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200391
392 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100393 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200394}
395
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100396static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200397{
398 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
399 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200400 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200401}
402
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100403static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200404{
405 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
406 struct sigmatel_spec *spec = codec->spec;
407 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
408
409 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
410 return 0;
411}
412
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100413static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200414{
415 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
416 struct sigmatel_spec *spec = codec->spec;
417 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
418
Mattc7d4b2f2005-06-27 14:59:41 +0200419 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200420 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
421}
422
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100423static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
424 struct snd_ctl_elem_info *uinfo)
425{
426 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
427 struct sigmatel_spec *spec = codec->spec;
428 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
429}
430
431static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
432 struct snd_ctl_elem_value *ucontrol)
433{
434 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
435 struct sigmatel_spec *spec = codec->spec;
436
437 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
438 return 0;
439}
440
441static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
442 struct snd_ctl_elem_value *ucontrol)
443{
444 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
445 struct sigmatel_spec *spec = codec->spec;
446
447 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
448 spec->mono_nid, &spec->cur_mmux);
449}
450
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200451#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
452
453static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
454 struct snd_ctl_elem_value *ucontrol)
455{
456 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100457 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200458 struct sigmatel_spec *spec = codec->spec;
459
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100460 ucontrol->value.integer.value[0] = !!(spec->aloopback &
461 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200462 return 0;
463}
464
465static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
466 struct snd_ctl_elem_value *ucontrol)
467{
468 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
469 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100470 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200471 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100472 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200473
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100474 idx_val = spec->aloopback_mask << idx;
475 if (ucontrol->value.integer.value[0])
476 val = spec->aloopback | idx_val;
477 else
478 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100479 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200480 return 0;
481
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100482 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200483
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100484 /* Only return the bits defined by the shift value of the
485 * first two bytes of the mask
486 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200487 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100488 kcontrol->private_value & 0xFFFF, 0x0);
489 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200490
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100491 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200492 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100493 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200494 } else {
495 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100496 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200497 }
498
499 snd_hda_codec_write_cache(codec, codec->afg, 0,
500 kcontrol->private_value >> 16, dac_mode);
501
502 return 1;
503}
504
Mattc7d4b2f2005-06-27 14:59:41 +0200505static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200506 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200507 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200508 {}
509};
510
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200511static struct hda_verb stac9200_eapd_init[] = {
512 /* set dac0mux for dac converter */
513 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
514 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
515 {}
516};
517
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100518static struct hda_verb stac92hd73xx_6ch_core_init[] = {
519 /* set master volume and direct control */
520 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
521 /* setup audio connections */
522 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
523 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
524 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
525 /* setup adcs to point to mixer */
526 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
527 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100528 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
529 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
530 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
531 /* setup import muxs */
532 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
533 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
534 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
535 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
536 {}
537};
538
Matthew Ranostayd654a662008-03-14 08:46:51 +0100539static struct hda_verb dell_eq_core_init[] = {
540 /* set master volume to max value without distortion
541 * and direct control */
542 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
543 /* setup audio connections */
544 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
545 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
546 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
547 /* setup adcs to point to mixer */
548 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
549 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
550 /* setup import muxs */
551 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
552 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
553 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
554 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
555 {}
556};
557
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100558static struct hda_verb dell_m6_core_init[] = {
559 /* set master volume and direct control */
560 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
561 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100562 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
563 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100564 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
565 /* setup adcs to point to mixer */
566 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
567 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
568 /* setup import muxs */
569 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
570 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
571 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
572 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
573 {}
574};
575
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100576static struct hda_verb stac92hd73xx_8ch_core_init[] = {
577 /* set master volume and direct control */
578 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
579 /* setup audio connections */
580 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
581 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
582 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
583 /* connect hp ports to dac3 */
584 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
585 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
586 /* setup adcs to point to mixer */
587 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
588 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100589 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
590 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
591 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
592 /* setup import muxs */
593 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
594 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
595 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
596 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
597 {}
598};
599
600static struct hda_verb stac92hd73xx_10ch_core_init[] = {
601 /* set master volume and direct control */
602 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
603 /* setup audio connections */
604 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
605 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
606 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
607 /* dac3 is connected to import3 mux */
608 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
609 /* connect hp ports to dac4 */
610 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
611 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
612 /* setup adcs to point to mixer */
613 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
614 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100615 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
616 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
617 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
618 /* setup import muxs */
619 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
620 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
621 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
622 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
623 {}
624};
625
Matthew Ranostaye035b842007-11-06 11:53:55 +0100626static struct hda_verb stac92hd71bxx_core_init[] = {
627 /* set master volume and direct control */
628 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
629 /* connect headphone jack to dac1 */
630 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100631 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
632 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
633 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
634 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
635 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100636};
637
638static struct hda_verb stac92hd71bxx_analog_core_init[] = {
639 /* set master volume and direct control */
640 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
641 /* connect headphone jack to dac1 */
642 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100643 /* connect ports 0d and 0f to audio mixer */
644 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
645 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100646 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100647 /* unmute dac0 input in audio mixer */
648 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100649 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
650 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
651 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
652 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100653 {}
654};
655
Tobin Davis8e21c342007-01-08 11:04:17 +0100656static struct hda_verb stac925x_core_init[] = {
657 /* set dac0mux for dac converter */
658 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
659 {}
660};
661
Mattc7d4b2f2005-06-27 14:59:41 +0200662static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200663 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200664 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200665 {}
666};
667
Tobin Davis93ed1502006-09-01 21:03:12 +0200668static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200669 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200670 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200671 /* unmute node 0x1b */
672 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
673 /* select node 0x03 as DAC */
674 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
675 {}
676};
677
Matt Porter3cc08dc2006-01-23 15:27:49 +0100678static struct hda_verb stac927x_core_init[] = {
679 /* set master volume and direct control */
680 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
681 {}
682};
683
Matt Porterf3302a52006-07-31 12:49:34 +0200684static struct hda_verb stac9205_core_init[] = {
685 /* set master volume and direct control */
686 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
687 {}
688};
689
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100690#define STAC_MONO_MUX \
691 { \
692 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
693 .name = "Mono Mux", \
694 .count = 1, \
695 .info = stac92xx_mono_mux_enum_info, \
696 .get = stac92xx_mono_mux_enum_get, \
697 .put = stac92xx_mono_mux_enum_put, \
698 }
699
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200700#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200701 { \
702 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
703 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200704 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200705 .info = stac92xx_mux_enum_info, \
706 .get = stac92xx_mux_enum_get, \
707 .put = stac92xx_mux_enum_put, \
708 }
709
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100710#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200711 { \
712 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
713 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100714 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200715 .info = stac92xx_aloopback_info, \
716 .get = stac92xx_aloopback_get, \
717 .put = stac92xx_aloopback_put, \
718 .private_value = verb_read | (verb_write << 16), \
719 }
720
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100721static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200722 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
723 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200724 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200725 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
726 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Mattc7d4b2f2005-06-27 14:59:41 +0200727 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200728 { } /* end */
729};
730
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100731static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100732 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
733
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100734 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
735 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
736
737 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
738 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
739
740 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
741 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
742
743 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
744 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
745
746 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
747 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
748
749 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
750 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
751
752 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
753 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
754 { } /* end */
755};
756
757static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100758 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
759
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100760 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
761 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
762
763 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
764 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
765
766 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
767 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
768
769 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
770 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
771
772 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
773 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
774
775 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
776 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
777
778 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
779 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
780 { } /* end */
781};
782
783static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100784 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
785
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100786 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
787 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
788
789 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
790 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
791
792 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
793 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
794
795 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
796 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
797
798 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
799 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
800
801 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
802 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
803
804 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
805 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
806 { } /* end */
807};
808
Matthew Ranostay541eee82007-12-14 12:08:04 +0100809static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100810 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100811
Matthew Ranostay9b359472007-11-07 13:03:12 +0100812 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
813 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
814 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
815
816 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
817 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
818 HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
819
820 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
821 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +0100822 { } /* end */
823};
824
Matthew Ranostay541eee82007-12-14 12:08:04 +0100825static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +0100826 STAC_INPUT_SOURCE(2),
827 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
828
Matthew Ranostay541eee82007-12-14 12:08:04 +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 { } /* end */
837};
838
Tobin Davis8e21c342007-01-08 11:04:17 +0100839static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200840 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +0100841 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
842 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT),
843 HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT),
844 { } /* end */
845};
846
Takashi Iwaid1d985f2006-11-23 19:27:12 +0100847static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200848 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100849 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200850
851 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
852 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
853 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT),
854
855 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
856 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
857 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT),
858
859 { } /* end */
860};
861
862/* This needs to be generated dynamically based on sequence */
863static struct snd_kcontrol_new stac922x_mixer[] = {
864 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200865 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
866 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
867 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT),
868
869 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
870 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
871 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT),
872 { } /* end */
873};
874
875
876static struct snd_kcontrol_new stac927x_mixer[] = {
877 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100878 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200879
880 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
881 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
882 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT),
883
884 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
885 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
886 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT),
887
888 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
889 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
890 HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +0200891 { } /* end */
892};
893
Takashi Iwai1697055e2007-12-18 18:05:52 +0100894static struct snd_kcontrol_new stac_dmux_mixer = {
895 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
896 .name = "Digital Input Source",
897 /* count set later */
898 .info = stac92xx_dmux_enum_info,
899 .get = stac92xx_dmux_enum_get,
900 .put = stac92xx_dmux_enum_put,
901};
902
Takashi Iwai2134ea42008-01-10 16:53:55 +0100903static const char *slave_vols[] = {
904 "Front Playback Volume",
905 "Surround Playback Volume",
906 "Center Playback Volume",
907 "LFE Playback Volume",
908 "Side Playback Volume",
909 "Headphone Playback Volume",
910 "Headphone Playback Volume",
911 "Speaker Playback Volume",
912 "External Speaker Playback Volume",
913 "Speaker2 Playback Volume",
914 NULL
915};
916
917static const char *slave_sws[] = {
918 "Front Playback Switch",
919 "Surround Playback Switch",
920 "Center Playback Switch",
921 "LFE Playback Switch",
922 "Side Playback Switch",
923 "Headphone Playback Switch",
924 "Headphone Playback Switch",
925 "Speaker Playback Switch",
926 "External Speaker Playback Switch",
927 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +0100928 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100929 NULL
930};
931
Matt2f2f4252005-04-13 14:45:30 +0200932static int stac92xx_build_controls(struct hda_codec *codec)
933{
934 struct sigmatel_spec *spec = codec->spec;
935 int err;
Mattc7d4b2f2005-06-27 14:59:41 +0200936 int i;
Matt2f2f4252005-04-13 14:45:30 +0200937
938 err = snd_hda_add_new_ctls(codec, spec->mixer);
939 if (err < 0)
940 return err;
Mattc7d4b2f2005-06-27 14:59:41 +0200941
942 for (i = 0; i < spec->num_mixers; i++) {
943 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
944 if (err < 0)
945 return err;
946 }
Takashi Iwai1697055e2007-12-18 18:05:52 +0100947 if (spec->num_dmuxes > 0) {
948 stac_dmux_mixer.count = spec->num_dmuxes;
949 err = snd_ctl_add(codec->bus->card,
950 snd_ctl_new1(&stac_dmux_mixer, codec));
951 if (err < 0)
952 return err;
953 }
Mattc7d4b2f2005-06-27 14:59:41 +0200954
Mattdabbed62005-06-14 10:19:34 +0200955 if (spec->multiout.dig_out_nid) {
956 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
957 if (err < 0)
958 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100959 err = snd_hda_create_spdif_share_sw(codec,
960 &spec->multiout);
961 if (err < 0)
962 return err;
963 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +0200964 }
965 if (spec->dig_in_nid) {
966 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
967 if (err < 0)
968 return err;
969 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100970
971 /* if we have no master control, let's create it */
972 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100973 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100974 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100975 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100976 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100977 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100978 if (err < 0)
979 return err;
980 }
981 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
982 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
983 NULL, slave_sws);
984 if (err < 0)
985 return err;
986 }
987
Mattdabbed62005-06-14 10:19:34 +0200988 return 0;
Matt2f2f4252005-04-13 14:45:30 +0200989}
990
Matt Porter403d1942005-11-29 15:00:51 +0100991static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +0200992 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +0200993 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
994};
995
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200996/*
997 STAC 9200 pin configs for
998 102801A8
999 102801DE
1000 102801E8
1001*/
1002static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001003 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1004 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001005};
1006
1007/*
1008 STAC 9200 pin configs for
1009 102801C0
1010 102801C1
1011*/
1012static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001013 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1014 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001015};
1016
1017/*
1018 STAC 9200 pin configs for
1019 102801C4 (Dell Dimension E310)
1020 102801C5
1021 102801C7
1022 102801D9
1023 102801DA
1024 102801E3
1025*/
1026static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001027 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1028 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001029};
1030
1031
1032/*
1033 STAC 9200-32 pin configs for
1034 102801B5 (Dell Inspiron 630m)
1035 102801D8 (Dell Inspiron 640m)
1036*/
1037static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001038 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1039 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001040};
1041
1042/*
1043 STAC 9200-32 pin configs for
1044 102801C2 (Dell Latitude D620)
1045 102801C8
1046 102801CC (Dell Latitude D820)
1047 102801D4
1048 102801D6
1049*/
1050static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001051 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1052 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001053};
1054
1055/*
1056 STAC 9200-32 pin configs for
1057 102801CE (Dell XPS M1710)
1058 102801CF (Dell Precision M90)
1059*/
1060static unsigned int dell9200_m23_pin_configs[8] = {
1061 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1062 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1063};
1064
1065/*
1066 STAC 9200-32 pin configs for
1067 102801C9
1068 102801CA
1069 102801CB (Dell Latitude 120L)
1070 102801D3
1071*/
1072static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001073 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1074 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001075};
1076
1077/*
1078 STAC 9200-32 pin configs for
1079 102801BD (Dell Inspiron E1505n)
1080 102801EE
1081 102801EF
1082*/
1083static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001084 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1085 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001086};
1087
1088/*
1089 STAC 9200-32 pin configs for
1090 102801F5 (Dell Inspiron 1501)
1091 102801F6
1092*/
1093static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001094 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1095 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001096};
1097
1098/*
1099 STAC 9200-32
1100 102801CD (Dell Inspiron E1705/9400)
1101*/
1102static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001103 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1104 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001105};
1106
Tobin Davisbf277782008-02-03 20:31:47 +01001107static unsigned int oqo9200_pin_configs[8] = {
1108 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1109 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1110};
1111
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001112
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001113static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1114 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001115 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001116 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1117 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1118 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1119 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1120 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1121 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1122 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1123 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1124 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1125 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001126 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001127};
1128
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001129static const char *stac9200_models[STAC_9200_MODELS] = {
1130 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001131 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001132 [STAC_9200_DELL_D21] = "dell-d21",
1133 [STAC_9200_DELL_D22] = "dell-d22",
1134 [STAC_9200_DELL_D23] = "dell-d23",
1135 [STAC_9200_DELL_M21] = "dell-m21",
1136 [STAC_9200_DELL_M22] = "dell-m22",
1137 [STAC_9200_DELL_M23] = "dell-m23",
1138 [STAC_9200_DELL_M24] = "dell-m24",
1139 [STAC_9200_DELL_M25] = "dell-m25",
1140 [STAC_9200_DELL_M26] = "dell-m26",
1141 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001142 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001143 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001144};
1145
1146static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1147 /* SigmaTel reference board */
1148 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1149 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001150 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001151 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1152 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001153 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001154 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1155 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1156 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1157 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1158 "unknown Dell", STAC_9200_DELL_D22),
1159 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1160 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001161 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001162 "Dell Latitude D620", STAC_9200_DELL_M22),
1163 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1164 "unknown Dell", STAC_9200_DELL_D23),
1165 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1166 "unknown Dell", STAC_9200_DELL_D23),
1167 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1168 "unknown Dell", STAC_9200_DELL_M22),
1169 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1170 "unknown Dell", STAC_9200_DELL_M24),
1171 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1172 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001173 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001174 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001175 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001176 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001177 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001178 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001179 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001180 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001181 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001182 "Dell Precision M90", STAC_9200_DELL_M23),
1183 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1184 "unknown Dell", STAC_9200_DELL_M22),
1185 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1186 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001187 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001188 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001189 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001190 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1191 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1192 "unknown Dell", STAC_9200_DELL_D23),
1193 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1194 "unknown Dell", STAC_9200_DELL_D23),
1195 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1196 "unknown Dell", STAC_9200_DELL_D21),
1197 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1198 "unknown Dell", STAC_9200_DELL_D23),
1199 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1200 "unknown Dell", STAC_9200_DELL_D21),
1201 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1202 "unknown Dell", STAC_9200_DELL_M25),
1203 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1204 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001205 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001206 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1207 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1208 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001209 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001210 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001211 /* Gateway machines needs EAPD to be set on resume */
1212 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1213 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1214 STAC_9200_GATEWAY),
1215 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1216 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001217 /* OQO Mobile */
1218 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001219 {} /* terminator */
1220};
1221
Tobin Davis8e21c342007-01-08 11:04:17 +01001222static unsigned int ref925x_pin_configs[8] = {
1223 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001224 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001225};
1226
1227static unsigned int stac925x_MA6_pin_configs[8] = {
1228 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1229 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1230};
1231
Tobin Davis2c11f952007-05-17 09:36:34 +02001232static unsigned int stac925x_PA6_pin_configs[8] = {
1233 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1234 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1235};
1236
Tobin Davis8e21c342007-01-08 11:04:17 +01001237static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001238 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1239 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001240};
1241
1242static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1243 [STAC_REF] = ref925x_pin_configs,
1244 [STAC_M2_2] = stac925xM2_2_pin_configs,
1245 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001246 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001247};
1248
1249static const char *stac925x_models[STAC_925x_MODELS] = {
1250 [STAC_REF] = "ref",
1251 [STAC_M2_2] = "m2-2",
1252 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001253 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001254};
1255
1256static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1257 /* SigmaTel reference board */
1258 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001259 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001260 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1261 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1262 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001263 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001264 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1265 {} /* terminator */
1266};
1267
Matthew Ranostaya7662642008-02-21 07:51:14 +01001268static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001269 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1270 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1271 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001272 0x01452050,
1273};
1274
1275static unsigned int dell_m6_pin_configs[13] = {
1276 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
1277 0x03a11020, 0x03011050, 0x4f0000f0, 0x4f0000f0,
1278 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1279 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001280};
1281
1282static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001283 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1284 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001285};
1286
1287static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1288 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001289 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001290};
1291
1292static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1293 /* SigmaTel reference board */
1294 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001295 "DFI LanParty", STAC_92HD73XX_REF),
1296 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1297 "unknown Dell", STAC_DELL_M6),
1298 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1299 "unknown Dell", STAC_DELL_M6),
1300 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1301 "unknown Dell", STAC_DELL_M6),
1302 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1303 "unknown Dell", STAC_DELL_M6),
1304 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1305 "unknown Dell", STAC_DELL_M6),
1306 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1307 "unknown Dell", STAC_DELL_M6),
1308 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1309 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001310 {} /* terminator */
1311};
1312
Matthew Ranostaye035b842007-11-06 11:53:55 +01001313static unsigned int ref92hd71bxx_pin_configs[10] = {
1314 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001315 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001316 0x90a000f0, 0x01452050,
1317};
1318
Matthew Ranostaya7662642008-02-21 07:51:14 +01001319static unsigned int dell_m4_1_pin_configs[13] = {
1320 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001321 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001322 0x40f000f0, 0x4f0000f0,
1323};
1324
1325static unsigned int dell_m4_2_pin_configs[13] = {
1326 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1327 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
1328 0x40f000f0, 0x044413b0,
1329};
1330
Matthew Ranostaye035b842007-11-06 11:53:55 +01001331static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1332 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001333 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1334 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001335};
1336
1337static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1338 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001339 [STAC_DELL_M4_1] = "dell-m4-1",
1340 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001341};
1342
1343static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1344 /* SigmaTel reference board */
1345 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1346 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001347 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1348 "unknown Dell", STAC_DELL_M4_1),
1349 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1350 "unknown Dell", STAC_DELL_M4_1),
1351 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1352 "unknown Dell", STAC_DELL_M4_1),
1353 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1354 "unknown Dell", STAC_DELL_M4_1),
1355 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1356 "unknown Dell", STAC_DELL_M4_1),
1357 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1358 "unknown Dell", STAC_DELL_M4_1),
1359 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1360 "unknown Dell", STAC_DELL_M4_1),
1361 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1362 "unknown Dell", STAC_DELL_M4_2),
1363 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1364 "unknown Dell", STAC_DELL_M4_2),
1365 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1366 "unknown Dell", STAC_DELL_M4_2),
1367 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1368 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001369 {} /* terminator */
1370};
1371
Matt Porter403d1942005-11-29 15:00:51 +01001372static unsigned int ref922x_pin_configs[10] = {
1373 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1374 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001375 0x40000100, 0x40000100,
1376};
1377
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001378/*
1379 STAC 922X pin configs for
1380 102801A7
1381 102801AB
1382 102801A9
1383 102801D1
1384 102801D2
1385*/
1386static unsigned int dell_922x_d81_pin_configs[10] = {
1387 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1388 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1389 0x01813122, 0x400001f2,
1390};
1391
1392/*
1393 STAC 922X pin configs for
1394 102801AC
1395 102801D0
1396*/
1397static unsigned int dell_922x_d82_pin_configs[10] = {
1398 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1399 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1400 0x01813122, 0x400001f1,
1401};
1402
1403/*
1404 STAC 922X pin configs for
1405 102801BF
1406*/
1407static unsigned int dell_922x_m81_pin_configs[10] = {
1408 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1409 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1410 0x40C003f1, 0x405003f0,
1411};
1412
1413/*
1414 STAC 9221 A1 pin configs for
1415 102801D7 (Dell XPS M1210)
1416*/
1417static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001418 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1419 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001420 0x508003f3, 0x405003f4,
1421};
1422
Matt Porter403d1942005-11-29 15:00:51 +01001423static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001424 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001425 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1426 0x02a19120, 0x40000100,
1427};
1428
1429static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001430 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1431 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001432 0x02a19320, 0x40000100,
1433};
1434
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001435static unsigned int intel_mac_v1_pin_configs[10] = {
1436 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1437 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001438 0x400000fc, 0x400000fb,
1439};
1440
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001441static unsigned int intel_mac_v2_pin_configs[10] = {
1442 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1443 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001444 0x400000fc, 0x400000fb,
1445};
1446
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001447static unsigned int intel_mac_v3_pin_configs[10] = {
1448 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1449 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1450 0x400000fc, 0x400000fb,
1451};
1452
1453static unsigned int intel_mac_v4_pin_configs[10] = {
1454 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1455 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1456 0x400000fc, 0x400000fb,
1457};
1458
1459static unsigned int intel_mac_v5_pin_configs[10] = {
1460 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1461 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1462 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001463};
1464
Takashi Iwai76c08822007-06-19 12:17:42 +02001465
Takashi Iwai19039bd2006-06-28 15:52:16 +02001466static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001467 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001468 [STAC_D945GTP3] = d945gtp3_pin_configs,
1469 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001470 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1471 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1472 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1473 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1474 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001475 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001476 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1477 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1478 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1479 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1480 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1481 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001482 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1483 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1484 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1485 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001486};
1487
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001488static const char *stac922x_models[STAC_922X_MODELS] = {
1489 [STAC_D945_REF] = "ref",
1490 [STAC_D945GTP5] = "5stack",
1491 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001492 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1493 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1494 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1495 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1496 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001497 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001498 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001499 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001500 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1501 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001502 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001503 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001504 [STAC_922X_DELL_D81] = "dell-d81",
1505 [STAC_922X_DELL_D82] = "dell-d82",
1506 [STAC_922X_DELL_M81] = "dell-m81",
1507 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001508};
1509
1510static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1511 /* SigmaTel reference board */
1512 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1513 "DFI LanParty", STAC_D945_REF),
1514 /* Intel 945G based systems */
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1516 "Intel D945G", STAC_D945GTP3),
1517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1518 "Intel D945G", STAC_D945GTP3),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1520 "Intel D945G", STAC_D945GTP3),
1521 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1522 "Intel D945G", STAC_D945GTP3),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1524 "Intel D945G", STAC_D945GTP3),
1525 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1526 "Intel D945G", STAC_D945GTP3),
1527 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1528 "Intel D945G", STAC_D945GTP3),
1529 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1530 "Intel D945G", STAC_D945GTP3),
1531 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1532 "Intel D945G", STAC_D945GTP3),
1533 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1534 "Intel D945G", STAC_D945GTP3),
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1536 "Intel D945G", STAC_D945GTP3),
1537 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1538 "Intel D945G", STAC_D945GTP3),
1539 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1540 "Intel D945G", STAC_D945GTP3),
1541 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1542 "Intel D945G", STAC_D945GTP3),
1543 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1544 "Intel D945G", STAC_D945GTP3),
1545 /* Intel D945G 5-stack systems */
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1547 "Intel D945G", STAC_D945GTP5),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1549 "Intel D945G", STAC_D945GTP5),
1550 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1551 "Intel D945G", STAC_D945GTP5),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1553 "Intel D945G", STAC_D945GTP5),
1554 /* Intel 945P based systems */
1555 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1556 "Intel D945P", STAC_D945GTP3),
1557 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1558 "Intel D945P", STAC_D945GTP3),
1559 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1560 "Intel D945P", STAC_D945GTP3),
1561 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1562 "Intel D945P", STAC_D945GTP3),
1563 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1564 "Intel D945P", STAC_D945GTP3),
1565 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1566 "Intel D945P", STAC_D945GTP5),
1567 /* other systems */
1568 /* Apple Mac Mini (early 2006) */
1569 SND_PCI_QUIRK(0x8384, 0x7680,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001570 "Mac Mini", STAC_INTEL_MAC_V3),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001571 /* Dell systems */
1572 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1573 "unknown Dell", STAC_922X_DELL_D81),
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1575 "unknown Dell", STAC_922X_DELL_D81),
1576 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1577 "unknown Dell", STAC_922X_DELL_D81),
1578 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1579 "unknown Dell", STAC_922X_DELL_D82),
1580 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1581 "unknown Dell", STAC_922X_DELL_M81),
1582 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1583 "unknown Dell", STAC_922X_DELL_D82),
1584 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1585 "unknown Dell", STAC_922X_DELL_D81),
1586 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1587 "unknown Dell", STAC_922X_DELL_D81),
1588 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1589 "Dell XPS M1210", STAC_922X_DELL_M82),
Matt Porter403d1942005-11-29 15:00:51 +01001590 {} /* terminator */
1591};
1592
Matt Porter3cc08dc2006-01-23 15:27:49 +01001593static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001594 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1595 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1596 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1597 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001598};
1599
Tobin Davis93ed1502006-09-01 21:03:12 +02001600static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001601 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1602 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1603 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1604 0x40000100, 0x40000100
1605};
1606
Tobin Davis93ed1502006-09-01 21:03:12 +02001607static unsigned int d965_5st_pin_configs[14] = {
1608 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1609 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1610 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1611 0x40000100, 0x40000100
1612};
1613
Tobin Davis4ff076e2007-08-07 11:48:12 +02001614static unsigned int dell_3st_pin_configs[14] = {
1615 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1616 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001617 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001618 0x40c003fc, 0x40000100
1619};
1620
Tobin Davis93ed1502006-09-01 21:03:12 +02001621static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001622 [STAC_D965_REF] = ref927x_pin_configs,
1623 [STAC_D965_3ST] = d965_3st_pin_configs,
1624 [STAC_D965_5ST] = d965_5st_pin_configs,
1625 [STAC_DELL_3ST] = dell_3st_pin_configs,
1626 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001627};
1628
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001629static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001630 [STAC_D965_REF] = "ref",
1631 [STAC_D965_3ST] = "3stack",
1632 [STAC_D965_5ST] = "5stack",
1633 [STAC_DELL_3ST] = "dell-3stack",
1634 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001635};
1636
1637static struct snd_pci_quirk stac927x_cfg_tbl[] = {
1638 /* SigmaTel reference board */
1639 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1640 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001641 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001642 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
1643 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02001644 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001645 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
1646 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
1648 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
1649 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
1650 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
1651 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
1652 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
1653 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
1654 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
1655 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
1656 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
1657 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
1658 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
1659 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
1660 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001661 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001662 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001663 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02001664 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
1665 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001666 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01001667 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
1668 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001669 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS),
1670 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
1671 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
1672 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
1673 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
1674 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02001675 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001676 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
1677 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
1678 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
1679 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
1680 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
1681 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
1682 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
1683 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
1684 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01001685 {} /* terminator */
1686};
1687
Matt Porterf3302a52006-07-31 12:49:34 +02001688static unsigned int ref9205_pin_configs[12] = {
1689 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001690 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02001691 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02001692};
1693
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001694/*
1695 STAC 9205 pin configs for
1696 102801F1
1697 102801F2
1698 102801FC
1699 102801FD
1700 10280204
1701 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001702 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001703*/
1704static unsigned int dell_9205_m42_pin_configs[12] = {
1705 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
1706 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
1707 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
1708};
1709
1710/*
1711 STAC 9205 pin configs for
1712 102801F9
1713 102801FA
1714 102801FE
1715 102801FF (Dell Precision M4300)
1716 10280206
1717 10280200
1718 10280201
1719*/
1720static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001721 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
1722 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
1723 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
1724};
1725
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001726static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001727 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
1728 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
1729 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
1730};
1731
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001732static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001733 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001734 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
1735 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
1736 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02001737};
1738
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001739static const char *stac9205_models[STAC_9205_MODELS] = {
1740 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001741 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001742 [STAC_9205_DELL_M43] = "dell-m43",
1743 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001744};
1745
1746static struct snd_pci_quirk stac9205_cfg_tbl[] = {
1747 /* SigmaTel reference board */
1748 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1749 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001750 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1751 "unknown Dell", STAC_9205_DELL_M42),
1752 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1753 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001754 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02001755 "Dell Precision", STAC_9205_DELL_M43),
1756 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
1757 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001758 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
1759 "Dell Precision", STAC_9205_DELL_M43),
Matthew Ranostaye45e4592007-09-10 23:09:42 +02001760 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
1761 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001762 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
1763 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001764 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1765 "unknown Dell", STAC_9205_DELL_M42),
1766 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1767 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001768 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
1769 "Dell Precision", STAC_9205_DELL_M43),
1770 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001771 "Dell Precision M4300", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001772 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
1773 "Dell Precision", STAC_9205_DELL_M43),
1774 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
1775 "Dell Inspiron", STAC_9205_DELL_M44),
1776 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
1777 "Dell Inspiron", STAC_9205_DELL_M44),
1778 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
1779 "Dell Inspiron", STAC_9205_DELL_M44),
1780 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
1781 "Dell Inspiron", STAC_9205_DELL_M44),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001782 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
1783 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02001784 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
1785 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01001786 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
1787 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02001788 {} /* terminator */
1789};
1790
Richard Fish11b44bb2006-08-23 18:31:34 +02001791static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
1792{
1793 int i;
1794 struct sigmatel_spec *spec = codec->spec;
1795
1796 if (! spec->bios_pin_configs) {
1797 spec->bios_pin_configs = kcalloc(spec->num_pins,
1798 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
1799 if (! spec->bios_pin_configs)
1800 return -ENOMEM;
1801 }
1802
1803 for (i = 0; i < spec->num_pins; i++) {
1804 hda_nid_t nid = spec->pin_nids[i];
1805 unsigned int pin_cfg;
1806
1807 pin_cfg = snd_hda_codec_read(codec, nid, 0,
1808 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
1809 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
1810 nid, pin_cfg);
1811 spec->bios_pin_configs[i] = pin_cfg;
1812 }
1813
1814 return 0;
1815}
1816
Matthew Ranostay87d48362007-07-17 11:52:24 +02001817static void stac92xx_set_config_reg(struct hda_codec *codec,
1818 hda_nid_t pin_nid, unsigned int pin_config)
1819{
1820 int i;
1821 snd_hda_codec_write(codec, pin_nid, 0,
1822 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
1823 pin_config & 0x000000ff);
1824 snd_hda_codec_write(codec, pin_nid, 0,
1825 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
1826 (pin_config & 0x0000ff00) >> 8);
1827 snd_hda_codec_write(codec, pin_nid, 0,
1828 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
1829 (pin_config & 0x00ff0000) >> 16);
1830 snd_hda_codec_write(codec, pin_nid, 0,
1831 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
1832 pin_config >> 24);
1833 i = snd_hda_codec_read(codec, pin_nid, 0,
1834 AC_VERB_GET_CONFIG_DEFAULT,
1835 0x00);
1836 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
1837 pin_nid, i);
1838}
1839
Matt2f2f4252005-04-13 14:45:30 +02001840static void stac92xx_set_config_regs(struct hda_codec *codec)
1841{
1842 int i;
1843 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02001844
Matthew Ranostay87d48362007-07-17 11:52:24 +02001845 if (!spec->pin_configs)
1846 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02001847
Matthew Ranostay87d48362007-07-17 11:52:24 +02001848 for (i = 0; i < spec->num_pins; i++)
1849 stac92xx_set_config_reg(codec, spec->pin_nids[i],
1850 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02001851}
Matt2f2f4252005-04-13 14:45:30 +02001852
Matt2f2f4252005-04-13 14:45:30 +02001853/*
1854 * Analog playback callbacks
1855 */
1856static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1857 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001858 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001859{
1860 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001861 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1862 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02001863}
1864
1865static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1866 struct hda_codec *codec,
1867 unsigned int stream_tag,
1868 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001869 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001870{
1871 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01001872 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02001873}
1874
1875static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1876 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001877 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001878{
1879 struct sigmatel_spec *spec = codec->spec;
1880 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1881}
1882
1883/*
Mattdabbed62005-06-14 10:19:34 +02001884 * Digital playback callbacks
1885 */
1886static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1887 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001888 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001889{
1890 struct sigmatel_spec *spec = codec->spec;
1891 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1892}
1893
1894static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1895 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001896 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02001897{
1898 struct sigmatel_spec *spec = codec->spec;
1899 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1900}
1901
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001902static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1903 struct hda_codec *codec,
1904 unsigned int stream_tag,
1905 unsigned int format,
1906 struct snd_pcm_substream *substream)
1907{
1908 struct sigmatel_spec *spec = codec->spec;
1909 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1910 stream_tag, format, substream);
1911}
1912
Mattdabbed62005-06-14 10:19:34 +02001913
1914/*
Matt2f2f4252005-04-13 14:45:30 +02001915 * Analog capture callbacks
1916 */
1917static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1918 struct hda_codec *codec,
1919 unsigned int stream_tag,
1920 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001921 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001922{
1923 struct sigmatel_spec *spec = codec->spec;
1924
1925 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1926 stream_tag, 0, format);
1927 return 0;
1928}
1929
1930static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1931 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001932 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02001933{
1934 struct sigmatel_spec *spec = codec->spec;
1935
Takashi Iwai888afa12008-03-18 09:57:50 +01001936 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Matt2f2f4252005-04-13 14:45:30 +02001937 return 0;
1938}
1939
Mattdabbed62005-06-14 10:19:34 +02001940static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
1941 .substreams = 1,
1942 .channels_min = 2,
1943 .channels_max = 2,
1944 /* NID is set in stac92xx_build_pcms */
1945 .ops = {
1946 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001947 .close = stac92xx_dig_playback_pcm_close,
1948 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02001949 },
1950};
1951
1952static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
1953 .substreams = 1,
1954 .channels_min = 2,
1955 .channels_max = 2,
1956 /* NID is set in stac92xx_build_pcms */
1957};
1958
Matt2f2f4252005-04-13 14:45:30 +02001959static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
1960 .substreams = 1,
1961 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02001962 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02001963 .nid = 0x02, /* NID to query formats and rates */
1964 .ops = {
1965 .open = stac92xx_playback_pcm_open,
1966 .prepare = stac92xx_playback_pcm_prepare,
1967 .cleanup = stac92xx_playback_pcm_cleanup
1968 },
1969};
1970
Matt Porter3cc08dc2006-01-23 15:27:49 +01001971static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
1972 .substreams = 1,
1973 .channels_min = 2,
1974 .channels_max = 2,
1975 .nid = 0x06, /* NID to query formats and rates */
1976 .ops = {
1977 .open = stac92xx_playback_pcm_open,
1978 .prepare = stac92xx_playback_pcm_prepare,
1979 .cleanup = stac92xx_playback_pcm_cleanup
1980 },
1981};
1982
Matt2f2f4252005-04-13 14:45:30 +02001983static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02001984 .channels_min = 2,
1985 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001986 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02001987 .ops = {
1988 .prepare = stac92xx_capture_pcm_prepare,
1989 .cleanup = stac92xx_capture_pcm_cleanup
1990 },
1991};
1992
1993static int stac92xx_build_pcms(struct hda_codec *codec)
1994{
1995 struct sigmatel_spec *spec = codec->spec;
1996 struct hda_pcm *info = spec->pcm_rec;
1997
1998 codec->num_pcms = 1;
1999 codec->pcm_info = info;
2000
Mattc7d4b2f2005-06-27 14:59:41 +02002001 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002002 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002003 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002004 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002005 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002006
2007 if (spec->alt_switch) {
2008 codec->num_pcms++;
2009 info++;
2010 info->name = "STAC92xx Analog Alt";
2011 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2012 }
Matt2f2f4252005-04-13 14:45:30 +02002013
Mattdabbed62005-06-14 10:19:34 +02002014 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2015 codec->num_pcms++;
2016 info++;
2017 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002018 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002019 if (spec->multiout.dig_out_nid) {
2020 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2021 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2022 }
2023 if (spec->dig_in_nid) {
2024 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2025 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2026 }
2027 }
2028
Matt2f2f4252005-04-13 14:45:30 +02002029 return 0;
2030}
2031
Takashi Iwaic960a032006-03-23 17:06:28 +01002032static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2033{
2034 unsigned int pincap = snd_hda_param_read(codec, nid,
2035 AC_PAR_PIN_CAP);
2036 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2037 if (pincap & AC_PINCAP_VREF_100)
2038 return AC_PINCTL_VREF_100;
2039 if (pincap & AC_PINCAP_VREF_80)
2040 return AC_PINCTL_VREF_80;
2041 if (pincap & AC_PINCAP_VREF_50)
2042 return AC_PINCTL_VREF_50;
2043 if (pincap & AC_PINCAP_VREF_GRD)
2044 return AC_PINCTL_VREF_GRD;
2045 return 0;
2046}
2047
Matt Porter403d1942005-11-29 15:00:51 +01002048static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2049
2050{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002051 snd_hda_codec_write_cache(codec, nid, 0,
2052 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002053}
2054
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002055#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002056
2057static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2058{
2059 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2060 struct sigmatel_spec *spec = codec->spec;
2061 int io_idx = kcontrol-> private_value & 0xff;
2062
2063 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2064 return 0;
2065}
2066
2067static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2068{
2069 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2070 struct sigmatel_spec *spec = codec->spec;
2071 hda_nid_t nid = kcontrol->private_value >> 8;
2072 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002073 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002074
2075 spec->io_switch[io_idx] = val;
2076
2077 if (val)
2078 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002079 else {
2080 unsigned int pinctl = AC_PINCTL_IN_EN;
2081 if (io_idx) /* set VREF for mic */
2082 pinctl |= stac92xx_get_vref(codec, nid);
2083 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2084 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002085
2086 /* check the auto-mute again: we need to mute/unmute the speaker
2087 * appropriately according to the pin direction
2088 */
2089 if (spec->hp_detect)
2090 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2091
Matt Porter403d1942005-11-29 15:00:51 +01002092 return 1;
2093}
2094
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002095#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2096
2097static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2098 struct snd_ctl_elem_value *ucontrol)
2099{
2100 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2101 struct sigmatel_spec *spec = codec->spec;
2102
2103 ucontrol->value.integer.value[0] = spec->clfe_swap;
2104 return 0;
2105}
2106
2107static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2108 struct snd_ctl_elem_value *ucontrol)
2109{
2110 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2111 struct sigmatel_spec *spec = codec->spec;
2112 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002113 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002114
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002115 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002116 return 0;
2117
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002118 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002119
2120 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2121 spec->clfe_swap ? 0x4 : 0x0);
2122
2123 return 1;
2124}
2125
Matt Porter403d1942005-11-29 15:00:51 +01002126#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2127 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2128 .name = xname, \
2129 .index = 0, \
2130 .info = stac92xx_io_switch_info, \
2131 .get = stac92xx_io_switch_get, \
2132 .put = stac92xx_io_switch_put, \
2133 .private_value = xpval, \
2134 }
2135
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002136#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2137 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2138 .name = xname, \
2139 .index = 0, \
2140 .info = stac92xx_clfe_switch_info, \
2141 .get = stac92xx_clfe_switch_get, \
2142 .put = stac92xx_clfe_switch_put, \
2143 .private_value = xpval, \
2144 }
Matt Porter403d1942005-11-29 15:00:51 +01002145
Mattc7d4b2f2005-06-27 14:59:41 +02002146enum {
2147 STAC_CTL_WIDGET_VOL,
2148 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002149 STAC_CTL_WIDGET_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002150 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002151 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002152};
2153
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002154static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002155 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2156 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002157 STAC_MONO_MUX,
Matt Porter403d1942005-11-29 15:00:51 +01002158 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002159 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002160};
2161
2162/* add dynamic controls */
2163static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
2164{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002165 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002166
2167 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2168 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2169
2170 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2171 if (! knew)
2172 return -ENOMEM;
2173 if (spec->kctl_alloc) {
2174 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2175 kfree(spec->kctl_alloc);
2176 }
2177 spec->kctl_alloc = knew;
2178 spec->num_kctl_alloc = num;
2179 }
2180
2181 knew = &spec->kctl_alloc[spec->num_kctl_used];
2182 *knew = stac92xx_control_templates[type];
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002183 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002184 if (! knew->name)
2185 return -ENOMEM;
2186 knew->private_value = val;
2187 spec->num_kctl_used++;
2188 return 0;
2189}
2190
Matt Porter403d1942005-11-29 15:00:51 +01002191/* flag inputs as additional dynamic lineouts */
2192static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2193{
2194 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002195 unsigned int wcaps, wtype;
2196 int i, num_dacs = 0;
2197
2198 /* use the wcaps cache to count all DACs available for line-outs */
2199 for (i = 0; i < codec->num_nodes; i++) {
2200 wcaps = codec->wcaps[i];
2201 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002202
Steve Longerbeam7b043892007-05-03 20:50:03 +02002203 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2204 num_dacs++;
2205 }
Matt Porter403d1942005-11-29 15:00:51 +01002206
Steve Longerbeam7b043892007-05-03 20:50:03 +02002207 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2208
Matt Porter403d1942005-11-29 15:00:51 +01002209 switch (cfg->line_outs) {
2210 case 3:
2211 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002212 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002213 cfg->line_out_pins[cfg->line_outs] =
2214 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002215 spec->line_switch = 1;
2216 cfg->line_outs++;
2217 }
2218 break;
2219 case 2:
2220 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002221 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002222 cfg->line_out_pins[cfg->line_outs] =
2223 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002224 spec->line_switch = 1;
2225 cfg->line_outs++;
2226 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002227 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002228 cfg->line_out_pins[cfg->line_outs] =
2229 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002230 spec->mic_switch = 1;
2231 cfg->line_outs++;
2232 }
2233 break;
2234 case 1:
2235 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002236 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002237 cfg->line_out_pins[cfg->line_outs] =
2238 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002239 spec->line_switch = 1;
2240 cfg->line_outs++;
2241 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002242 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002243 cfg->line_out_pins[cfg->line_outs] =
2244 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002245 spec->mic_switch = 1;
2246 cfg->line_outs++;
2247 }
2248 break;
2249 }
2250
2251 return 0;
2252}
2253
Steve Longerbeam7b043892007-05-03 20:50:03 +02002254
2255static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2256{
2257 int i;
2258
2259 for (i = 0; i < spec->multiout.num_dacs; i++) {
2260 if (spec->multiout.dac_nids[i] == nid)
2261 return 1;
2262 }
2263
2264 return 0;
2265}
2266
Matt Porter3cc08dc2006-01-23 15:27:49 +01002267/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002268 * Fill in the dac_nids table from the parsed pin configuration
2269 * This function only works when every pin in line_out_pins[]
2270 * contains atleast one DAC in its connection list. Some 92xx
2271 * codecs are not connected directly to a DAC, such as the 9200
2272 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002273 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002274static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002275 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002276{
2277 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002278 int i, j, conn_len = 0;
2279 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2280 unsigned int wcaps, wtype;
2281
Mattc7d4b2f2005-06-27 14:59:41 +02002282 for (i = 0; i < cfg->line_outs; i++) {
2283 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002284 conn_len = snd_hda_get_connections(codec, nid, conn,
2285 HDA_MAX_CONNECTIONS);
2286 for (j = 0; j < conn_len; j++) {
2287 wcaps = snd_hda_param_read(codec, conn[j],
2288 AC_PAR_AUDIO_WIDGET_CAP);
2289 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002290 if (wtype != AC_WID_AUD_OUT ||
2291 (wcaps & AC_WCAP_DIGITAL))
2292 continue;
2293 /* conn[j] is a DAC routed to this line-out */
2294 if (!is_in_dac_nids(spec, conn[j]))
2295 break;
2296 }
2297
2298 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002299 if (spec->multiout.num_dacs > 0) {
2300 /* we have already working output pins,
2301 * so let's drop the broken ones again
2302 */
2303 cfg->line_outs = spec->multiout.num_dacs;
2304 break;
2305 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002306 /* error out, no available DAC found */
2307 snd_printk(KERN_ERR
2308 "%s: No available DAC for pin 0x%x\n",
2309 __func__, nid);
2310 return -ENODEV;
2311 }
2312
2313 spec->multiout.dac_nids[i] = conn[j];
2314 spec->multiout.num_dacs++;
2315 if (conn_len > 1) {
2316 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002317 snd_hda_codec_write_cache(codec, nid, 0,
2318 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002319
2320 }
Mattc7d4b2f2005-06-27 14:59:41 +02002321 }
2322
Steve Longerbeam7b043892007-05-03 20:50:03 +02002323 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2324 spec->multiout.num_dacs,
2325 spec->multiout.dac_nids[0],
2326 spec->multiout.dac_nids[1],
2327 spec->multiout.dac_nids[2],
2328 spec->multiout.dac_nids[3],
2329 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002330 return 0;
2331}
2332
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002333/* create volume control/switch for the given prefx type */
2334static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2335{
2336 char name[32];
2337 int err;
2338
2339 sprintf(name, "%s Playback Volume", pfx);
2340 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2341 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2342 if (err < 0)
2343 return err;
2344 sprintf(name, "%s Playback Switch", pfx);
2345 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2346 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2347 if (err < 0)
2348 return err;
2349 return 0;
2350}
2351
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002352static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2353{
2354 if (!spec->multiout.hp_nid)
2355 spec->multiout.hp_nid = nid;
2356 else if (spec->multiout.num_dacs > 4) {
2357 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2358 return 1;
2359 } else {
2360 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2361 spec->multiout.num_dacs++;
2362 }
2363 return 0;
2364}
2365
2366static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2367{
2368 if (is_in_dac_nids(spec, nid))
2369 return 1;
2370 if (spec->multiout.hp_nid == nid)
2371 return 1;
2372 return 0;
2373}
2374
Mattc7d4b2f2005-06-27 14:59:41 +02002375/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002376static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002377 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002378{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002379 static const char *chname[4] = {
2380 "Front", "Surround", NULL /*CLFE*/, "Side"
2381 };
Mattc7d4b2f2005-06-27 14:59:41 +02002382 hda_nid_t nid;
2383 int i, err;
2384
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002385 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002386 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002387
2388
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002389 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002390 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002391 continue;
2392
2393 nid = spec->multiout.dac_nids[i];
2394
2395 if (i == 2) {
2396 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002397 err = create_controls(spec, "Center", nid, 1);
2398 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002399 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002400 err = create_controls(spec, "LFE", nid, 2);
2401 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002402 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002403
2404 wid_caps = get_wcaps(codec, nid);
2405
2406 if (wid_caps & AC_WCAP_LR_SWAP) {
2407 err = stac92xx_add_control(spec,
2408 STAC_CTL_WIDGET_CLFE_SWITCH,
2409 "Swap Center/LFE Playback Switch", nid);
2410
2411 if (err < 0)
2412 return err;
2413 }
2414
Mattc7d4b2f2005-06-27 14:59:41 +02002415 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002416 err = create_controls(spec, chname[i], nid, 3);
2417 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002418 return err;
2419 }
2420 }
2421
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002422 if (spec->line_switch) {
2423 nid = cfg->input_pins[AUTO_PIN_LINE];
2424 pincap = snd_hda_param_read(codec, nid,
2425 AC_PAR_PIN_CAP);
2426 if (pincap & AC_PINCAP_OUT) {
2427 err = stac92xx_add_control(spec,
2428 STAC_CTL_WIDGET_IO_SWITCH,
2429 "Line In as Output Switch", nid << 8);
2430 if (err < 0)
2431 return err;
2432 }
2433 }
Matt Porter403d1942005-11-29 15:00:51 +01002434
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002435 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002436 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002437 unsigned int mic_pin = AUTO_PIN_MIC;
2438again:
2439 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002440 def_conf = snd_hda_codec_read(codec, nid, 0,
2441 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002442 /* some laptops have an internal analog microphone
2443 * which can't be used as a output */
2444 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2445 pincap = snd_hda_param_read(codec, nid,
2446 AC_PAR_PIN_CAP);
2447 if (pincap & AC_PINCAP_OUT) {
2448 err = stac92xx_add_control(spec,
2449 STAC_CTL_WIDGET_IO_SWITCH,
2450 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002451 nid = snd_hda_codec_read(codec, nid, 0,
2452 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2453 if (!check_in_dac_nids(spec, nid))
2454 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002455 if (err < 0)
2456 return err;
2457 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002458 } else if (mic_pin == AUTO_PIN_MIC) {
2459 mic_pin = AUTO_PIN_FRONT_MIC;
2460 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002461 }
2462 }
Matt Porter403d1942005-11-29 15:00:51 +01002463
Mattc7d4b2f2005-06-27 14:59:41 +02002464 return 0;
2465}
2466
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002467/* add playback controls for Speaker and HP outputs */
2468static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2469 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002470{
2471 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002472 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002473 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002474
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002475 old_num_dacs = spec->multiout.num_dacs;
2476 for (i = 0; i < cfg->hp_outs; i++) {
2477 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2478 if (wid_caps & AC_WCAP_UNSOL_CAP)
2479 spec->hp_detect = 1;
2480 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2481 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2482 if (check_in_dac_nids(spec, nid))
2483 nid = 0;
2484 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002485 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002486 add_spec_dacs(spec, nid);
2487 }
2488 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002489 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002490 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2491 if (check_in_dac_nids(spec, nid))
2492 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002493 if (! nid)
2494 continue;
2495 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002496 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002497 for (i = 0; i < cfg->line_outs; i++) {
2498 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2499 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2500 if (check_in_dac_nids(spec, nid))
2501 nid = 0;
2502 if (! nid)
2503 continue;
2504 add_spec_dacs(spec, nid);
2505 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002506 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2507 static const char *pfxs[] = {
2508 "Speaker", "External Speaker", "Speaker2",
2509 };
2510 err = create_controls(spec, pfxs[i - old_num_dacs],
2511 spec->multiout.dac_nids[i], 3);
2512 if (err < 0)
2513 return err;
2514 }
2515 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002516 err = create_controls(spec, "Headphone",
2517 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002518 if (err < 0)
2519 return err;
2520 }
Mattc7d4b2f2005-06-27 14:59:41 +02002521
2522 return 0;
2523}
2524
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002525/* labels for mono mux outputs */
2526static const char *stac92xx_mono_labels[3] = {
2527 "DAC0", "DAC1", "Mixer"
2528};
2529
2530/* create mono mux for mono out on capable codecs */
2531static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2532{
2533 struct sigmatel_spec *spec = codec->spec;
2534 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2535 int i, num_cons;
2536 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2537
2538 num_cons = snd_hda_get_connections(codec,
2539 spec->mono_nid,
2540 con_lst,
2541 HDA_MAX_NUM_INPUTS);
2542 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2543 return -EINVAL;
2544
2545 for (i = 0; i < num_cons; i++) {
2546 mono_mux->items[mono_mux->num_items].label =
2547 stac92xx_mono_labels[i];
2548 mono_mux->items[mono_mux->num_items].index = i;
2549 mono_mux->num_items++;
2550 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002551
2552 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2553 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002554}
2555
Matt Porter8b657272006-10-26 17:12:59 +02002556/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01002557static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02002558 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
2559 "Digital Mic 3", "Digital Mic 4"
2560};
2561
2562/* create playback/capture controls for input pins on dmic capable codecs */
2563static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
2564 const struct auto_pin_cfg *cfg)
2565{
2566 struct sigmatel_spec *spec = codec->spec;
2567 struct hda_input_mux *dimux = &spec->private_dimux;
2568 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002569 int err, i, j;
2570 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02002571
2572 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
2573 dimux->items[dimux->num_items].index = 0;
2574 dimux->num_items++;
2575
2576 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002577 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02002578 int index;
2579 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002580 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02002581 unsigned int def_conf;
2582
2583 def_conf = snd_hda_codec_read(codec,
2584 spec->dmic_nids[i],
2585 0,
2586 AC_VERB_GET_CONFIG_DEFAULT,
2587 0);
2588 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
2589 continue;
2590
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002591 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02002592 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002593 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02002594 con_lst,
2595 HDA_MAX_NUM_INPUTS);
2596 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002597 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02002598 index = j;
2599 goto found;
2600 }
2601 continue;
2602found:
Matthew Ranostay0678acc2008-01-08 12:10:50 +01002603 wcaps = get_wcaps(codec, nid);
2604
2605 if (wcaps & AC_WCAP_OUT_AMP) {
2606 sprintf(name, "%s Capture Volume",
2607 stac92xx_dmic_labels[dimux->num_items]);
2608
2609 err = stac92xx_add_control(spec,
2610 STAC_CTL_WIDGET_VOL,
2611 name,
2612 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2613 if (err < 0)
2614 return err;
2615 }
2616
Matt Porter8b657272006-10-26 17:12:59 +02002617 dimux->items[dimux->num_items].label =
2618 stac92xx_dmic_labels[dimux->num_items];
2619 dimux->items[dimux->num_items].index = index;
2620 dimux->num_items++;
2621 }
2622
2623 return 0;
2624}
2625
Mattc7d4b2f2005-06-27 14:59:41 +02002626/* create playback/capture controls for input pins */
2627static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
2628{
2629 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002630 struct hda_input_mux *imux = &spec->private_imux;
2631 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
2632 int i, j, k;
2633
2634 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02002635 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02002636
Takashi Iwai314634b2006-09-21 11:56:18 +02002637 if (!cfg->input_pins[i])
2638 continue;
2639 index = -1;
2640 for (j = 0; j < spec->num_muxes; j++) {
2641 int num_cons;
2642 num_cons = snd_hda_get_connections(codec,
2643 spec->mux_nids[j],
2644 con_lst,
2645 HDA_MAX_NUM_INPUTS);
2646 for (k = 0; k < num_cons; k++)
2647 if (con_lst[k] == cfg->input_pins[i]) {
2648 index = k;
2649 goto found;
2650 }
Mattc7d4b2f2005-06-27 14:59:41 +02002651 }
Takashi Iwai314634b2006-09-21 11:56:18 +02002652 continue;
2653 found:
2654 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2655 imux->items[imux->num_items].index = index;
2656 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02002657 }
2658
Steve Longerbeam7b043892007-05-03 20:50:03 +02002659 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02002660 /*
2661 * Set the current input for the muxes.
2662 * The STAC9221 has two input muxes with identical source
2663 * NID lists. Hopefully this won't get confused.
2664 */
2665 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002666 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
2667 AC_VERB_SET_CONNECT_SEL,
2668 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002669 }
2670 }
2671
Mattc7d4b2f2005-06-27 14:59:41 +02002672 return 0;
2673}
2674
Mattc7d4b2f2005-06-27 14:59:41 +02002675static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
2676{
2677 struct sigmatel_spec *spec = codec->spec;
2678 int i;
2679
2680 for (i = 0; i < spec->autocfg.line_outs; i++) {
2681 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2682 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
2683 }
2684}
2685
2686static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
2687{
2688 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002689 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02002690
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002691 for (i = 0; i < spec->autocfg.hp_outs; i++) {
2692 hda_nid_t pin;
2693 pin = spec->autocfg.hp_pins[i];
2694 if (pin) /* connect to front */
2695 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
2696 }
2697 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
2698 hda_nid_t pin;
2699 pin = spec->autocfg.speaker_pins[i];
2700 if (pin) /* connect to front */
2701 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
2702 }
Mattc7d4b2f2005-06-27 14:59:41 +02002703}
2704
Matt Porter3cc08dc2006-01-23 15:27:49 +01002705static 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 +02002706{
2707 struct sigmatel_spec *spec = codec->spec;
2708 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002709 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002710
Matt Porter8b657272006-10-26 17:12:59 +02002711 if ((err = snd_hda_parse_pin_def_config(codec,
2712 &spec->autocfg,
2713 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002714 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002715 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01002716 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002717
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002718 /* If we have no real line-out pin and multiple hp-outs, HPs should
2719 * be set up as multi-channel outputs.
2720 */
2721 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
2722 spec->autocfg.hp_outs > 1) {
2723 /* Copy hp_outs to line_outs, backup line_outs in
2724 * speaker_outs so that the following routines can handle
2725 * HP pins as primary outputs.
2726 */
2727 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
2728 sizeof(spec->autocfg.line_out_pins));
2729 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
2730 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
2731 sizeof(spec->autocfg.hp_pins));
2732 spec->autocfg.line_outs = spec->autocfg.hp_outs;
2733 hp_speaker_swap = 1;
2734 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002735 if (spec->autocfg.mono_out_pin) {
2736 int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
2737 & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
2738 u32 caps = query_amp_caps(codec,
2739 spec->autocfg.mono_out_pin, dir);
2740 hda_nid_t conn_list[1];
2741
2742 /* get the mixer node and then the mono mux if it exists */
2743 if (snd_hda_get_connections(codec,
2744 spec->autocfg.mono_out_pin, conn_list, 1) &&
2745 snd_hda_get_connections(codec, conn_list[0],
2746 conn_list, 1)) {
2747
2748 int wcaps = get_wcaps(codec, conn_list[0]);
2749 int wid_type = (wcaps & AC_WCAP_TYPE)
2750 >> AC_WCAP_TYPE_SHIFT;
2751 /* LR swap check, some stac925x have a mux that
2752 * changes the DACs output path instead of the
2753 * mono-mux path.
2754 */
2755 if (wid_type == AC_WID_AUD_SEL &&
2756 !(wcaps & AC_WCAP_LR_SWAP))
2757 spec->mono_nid = conn_list[0];
2758 }
2759 /* all mono outs have a least a mute/unmute switch */
2760 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
2761 "Mono Playback Switch",
2762 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2763 1, 0, dir));
2764 if (err < 0)
2765 return err;
2766 /* check to see if there is volume support for the amp */
2767 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
2768 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
2769 "Mono Playback Volume",
2770 HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
2771 1, 0, dir));
2772 if (err < 0)
2773 return err;
2774 }
2775
2776 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
2777 AC_PINCTL_OUT_EN);
2778 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002779
Matt Porter403d1942005-11-29 15:00:51 +01002780 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
2781 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02002782 if (spec->multiout.num_dacs == 0)
2783 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2784 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02002785
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002786 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
2787
2788 if (err < 0)
2789 return err;
2790
Jiang Zhebcecd9b2007-11-12 12:57:03 +01002791 if (hp_speaker_swap == 1) {
2792 /* Restore the hp_outs and line_outs */
2793 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
2794 sizeof(spec->autocfg.line_out_pins));
2795 spec->autocfg.hp_outs = spec->autocfg.line_outs;
2796 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
2797 sizeof(spec->autocfg.speaker_pins));
2798 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
2799 memset(spec->autocfg.speaker_pins, 0,
2800 sizeof(spec->autocfg.speaker_pins));
2801 spec->autocfg.speaker_outs = 0;
2802 }
2803
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002804 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
2805
2806 if (err < 0)
2807 return err;
2808
2809 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
2810
2811 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002812 return err;
2813
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002814 if (spec->mono_nid > 0) {
2815 err = stac92xx_auto_create_mono_output_ctls(codec);
2816 if (err < 0)
2817 return err;
2818 }
2819
Matt Porter8b657272006-10-26 17:12:59 +02002820 if (spec->num_dmics > 0)
2821 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
2822 &spec->autocfg)) < 0)
2823 return err;
2824
Mattc7d4b2f2005-06-27 14:59:41 +02002825 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01002826 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02002827 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02002828
Takashi Iwai82bc9552006-03-21 11:24:42 +01002829 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002830 spec->multiout.dig_out_nid = dig_out;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002831 if (spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01002832 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02002833
2834 if (spec->kctl_alloc)
2835 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2836
2837 spec->input_mux = &spec->private_imux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01002838 if (!spec->dinput_mux)
2839 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002840 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02002841
2842 return 1;
2843}
2844
Takashi Iwai82bc9552006-03-21 11:24:42 +01002845/* add playback controls for HP output */
2846static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
2847 struct auto_pin_cfg *cfg)
2848{
2849 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002850 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01002851 unsigned int wid_caps;
2852
2853 if (! pin)
2854 return 0;
2855
2856 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02002857 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01002858 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002859
2860 return 0;
2861}
2862
Richard Fish160ea0d2006-09-06 13:58:25 +02002863/* add playback controls for LFE output */
2864static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
2865 struct auto_pin_cfg *cfg)
2866{
2867 struct sigmatel_spec *spec = codec->spec;
2868 int err;
2869 hda_nid_t lfe_pin = 0x0;
2870 int i;
2871
2872 /*
2873 * search speaker outs and line outs for a mono speaker pin
2874 * with an amp. If one is found, add LFE controls
2875 * for it.
2876 */
2877 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
2878 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002879 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002880 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2881 if (wcaps == AC_WCAP_OUT_AMP)
2882 /* found a mono speaker with an amp, must be lfe */
2883 lfe_pin = pin;
2884 }
2885
2886 /* if speaker_outs is 0, then speakers may be in line_outs */
2887 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
2888 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
2889 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002890 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01002891 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02002892 AC_VERB_GET_CONFIG_DEFAULT,
2893 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01002894 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01002895 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02002896 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
2897 if (wcaps == AC_WCAP_OUT_AMP)
2898 /* found a mono speaker with an amp,
2899 must be lfe */
2900 lfe_pin = pin;
2901 }
2902 }
2903 }
2904
2905 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002906 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02002907 if (err < 0)
2908 return err;
2909 }
2910
2911 return 0;
2912}
2913
Mattc7d4b2f2005-06-27 14:59:41 +02002914static int stac9200_parse_auto_config(struct hda_codec *codec)
2915{
2916 struct sigmatel_spec *spec = codec->spec;
2917 int err;
2918
Kailang Yangdf694da2005-12-05 19:42:22 +01002919 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002920 return err;
2921
2922 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
2923 return err;
2924
Takashi Iwai82bc9552006-03-21 11:24:42 +01002925 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
2926 return err;
2927
Richard Fish160ea0d2006-09-06 13:58:25 +02002928 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
2929 return err;
2930
Takashi Iwai82bc9552006-03-21 11:24:42 +01002931 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002932 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01002933 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02002934 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02002935
2936 if (spec->kctl_alloc)
2937 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2938
2939 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02002940 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02002941
2942 return 1;
2943}
2944
Sam Revitch62fe78e2006-05-10 15:09:17 +02002945/*
2946 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
2947 * funky external mute control using GPIO pins.
2948 */
2949
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002950static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002951 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02002952{
2953 unsigned int gpiostate, gpiomask, gpiodir;
2954
2955 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
2956 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002957 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02002958
2959 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
2960 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002961 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002962
2963 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
2964 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01002965 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02002966
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002967 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002968 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
2969
2970 snd_hda_codec_write(codec, codec->afg, 0,
2971 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002972 snd_hda_codec_read(codec, codec->afg, 0,
2973 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002974
2975 msleep(1);
2976
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01002977 snd_hda_codec_read(codec, codec->afg, 0,
2978 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02002979}
2980
Takashi Iwai314634b2006-09-21 11:56:18 +02002981static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
2982 unsigned int event)
2983{
2984 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02002985 snd_hda_codec_write_cache(codec, nid, 0,
2986 AC_VERB_SET_UNSOLICITED_ENABLE,
2987 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02002988}
2989
Matthew Ranostaya64135a2008-01-10 16:55:06 +01002990static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
2991{
2992 int i;
2993 for (i = 0; i < cfg->hp_outs; i++)
2994 if (cfg->hp_pins[i] == nid)
2995 return 1; /* nid is a HP-Out */
2996
2997 return 0; /* nid is not a HP-Out */
2998};
2999
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003000static void stac92xx_power_down(struct hda_codec *codec)
3001{
3002 struct sigmatel_spec *spec = codec->spec;
3003
3004 /* power down inactive DACs */
3005 hda_nid_t *dac;
3006 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003007 if (!is_in_dac_nids(spec, *dac) &&
3008 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003009 snd_hda_codec_write_cache(codec, *dac, 0,
3010 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3011}
3012
Mattc7d4b2f2005-06-27 14:59:41 +02003013static int stac92xx_init(struct hda_codec *codec)
3014{
3015 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003016 struct auto_pin_cfg *cfg = &spec->autocfg;
3017 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003018
Mattc7d4b2f2005-06-27 14:59:41 +02003019 snd_hda_sequence_write(codec, spec->init);
3020
Takashi Iwai82bc9552006-03-21 11:24:42 +01003021 /* set up pins */
3022 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003023 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003024 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003025 enable_pin_detect(codec, cfg->hp_pins[i],
3026 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003027 /* force to enable the first line-out; the others are set up
3028 * in unsol_event
3029 */
3030 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3031 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003032 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003033 /* fake event to set up pins */
3034 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3035 } else {
3036 stac92xx_auto_init_multi_out(codec);
3037 stac92xx_auto_init_hp_out(codec);
3038 }
3039 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003040 hda_nid_t nid = cfg->input_pins[i];
3041 if (nid) {
3042 unsigned int pinctl = AC_PINCTL_IN_EN;
3043 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3044 pinctl |= stac92xx_get_vref(codec, nid);
3045 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3046 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003047 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003048 for (i = 0; i < spec->num_dmics; i++)
3049 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3050 AC_PINCTL_IN_EN);
3051 for (i = 0; i < spec->num_pwrs; i++) {
3052 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3053 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3054 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3055 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003056 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3057 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003058 /* outputs are only ports capable of power management
3059 * any attempts on powering down a input port cause the
3060 * referenced VREF to act quirky.
3061 */
3062 if (pinctl & AC_PINCTL_IN_EN)
3063 continue;
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003064 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
3065 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003066 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3067 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3068 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003069 if (spec->dac_list)
3070 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003071 if (cfg->dig_out_pin)
3072 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3073 AC_PINCTL_OUT_EN);
3074 if (cfg->dig_in_pin)
3075 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3076 AC_PINCTL_IN_EN);
3077
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003078 stac_gpio_set(codec, spec->gpio_mask,
3079 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003080
Mattc7d4b2f2005-06-27 14:59:41 +02003081 return 0;
3082}
3083
Matt2f2f4252005-04-13 14:45:30 +02003084static void stac92xx_free(struct hda_codec *codec)
3085{
Mattc7d4b2f2005-06-27 14:59:41 +02003086 struct sigmatel_spec *spec = codec->spec;
3087 int i;
3088
3089 if (! spec)
3090 return;
3091
3092 if (spec->kctl_alloc) {
3093 for (i = 0; i < spec->num_kctl_used; i++)
3094 kfree(spec->kctl_alloc[i].name);
3095 kfree(spec->kctl_alloc);
3096 }
3097
Richard Fish11b44bb2006-08-23 18:31:34 +02003098 if (spec->bios_pin_configs)
3099 kfree(spec->bios_pin_configs);
3100
Mattc7d4b2f2005-06-27 14:59:41 +02003101 kfree(spec);
Matt2f2f4252005-04-13 14:45:30 +02003102}
3103
Matt4e550962005-07-04 17:51:39 +02003104static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3105 unsigned int flag)
3106{
3107 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3108 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003109
Takashi Iwaif9acba42007-05-29 18:01:06 +02003110 if (pin_ctl & AC_PINCTL_IN_EN) {
3111 /*
3112 * we need to check the current set-up direction of
3113 * shared input pins since they can be switched via
3114 * "xxx as Output" mixer switch
3115 */
3116 struct sigmatel_spec *spec = codec->spec;
3117 struct auto_pin_cfg *cfg = &spec->autocfg;
3118 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3119 spec->line_switch) ||
3120 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3121 spec->mic_switch))
3122 return;
3123 }
3124
Steve Longerbeam7b043892007-05-03 20:50:03 +02003125 /* if setting pin direction bits, clear the current
3126 direction bits first */
3127 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3128 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3129
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003130 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003131 AC_VERB_SET_PIN_WIDGET_CONTROL,
3132 pin_ctl | flag);
3133}
3134
3135static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3136 unsigned int flag)
3137{
3138 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3139 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003140 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003141 AC_VERB_SET_PIN_WIDGET_CONTROL,
3142 pin_ctl & ~flag);
3143}
3144
Jiang Zhe40c1d302007-11-12 13:05:16 +01003145static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003146{
3147 if (!nid)
3148 return 0;
3149 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003150 & (1 << 31)) {
3151 unsigned int pinctl;
3152 pinctl = snd_hda_codec_read(codec, nid, 0,
3153 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3154 if (pinctl & AC_PINCTL_IN_EN)
3155 return 0; /* mic- or line-input */
3156 else
3157 return 1; /* HP-output */
3158 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003159 return 0;
3160}
3161
3162static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003163{
3164 struct sigmatel_spec *spec = codec->spec;
3165 struct auto_pin_cfg *cfg = &spec->autocfg;
3166 int i, presence;
3167
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003168 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003169 if (spec->gpio_mute)
3170 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3171 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3172
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003173 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003174 if (presence)
3175 break;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003176 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003177 }
Matt4e550962005-07-04 17:51:39 +02003178
3179 if (presence) {
3180 /* disable lineouts, enable hp */
3181 for (i = 0; i < cfg->line_outs; i++)
3182 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3183 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003184 for (i = 0; i < cfg->speaker_outs; i++)
3185 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3186 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003187 if (spec->eapd_mask)
3188 stac_gpio_set(codec, spec->gpio_mask,
3189 spec->gpio_dir, spec->gpio_data &
3190 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003191 } else {
3192 /* enable lineouts, disable hp */
3193 for (i = 0; i < cfg->line_outs; i++)
3194 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3195 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003196 for (i = 0; i < cfg->speaker_outs; i++)
3197 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3198 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003199 if (spec->eapd_mask)
3200 stac_gpio_set(codec, spec->gpio_mask,
3201 spec->gpio_dir, spec->gpio_data |
3202 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003203 }
3204}
3205
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003206static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3207{
3208 struct sigmatel_spec *spec = codec->spec;
3209 hda_nid_t nid = spec->pwr_nids[idx];
3210 int presence, val;
3211 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3212 & 0x000000ff;
3213 presence = get_hp_pin_presence(codec, nid);
3214 idx = 1 << idx;
3215
3216 if (presence)
3217 val &= ~idx;
3218 else
3219 val |= idx;
3220
3221 /* power down unused output ports */
3222 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3223};
3224
Takashi Iwai314634b2006-09-21 11:56:18 +02003225static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3226{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003227 struct sigmatel_spec *spec = codec->spec;
3228 int idx = res >> 26 & 0x0f;
3229
3230 switch ((res >> 26) & 0x30) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003231 case STAC_HP_EVENT:
3232 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003233 /* fallthru */
3234 case STAC_PWR_EVENT:
3235 if (spec->num_pwrs > 0)
3236 stac92xx_pin_sense(codec, idx);
Takashi Iwai314634b2006-09-21 11:56:18 +02003237 }
3238}
3239
Takashi Iwaicb53c622007-08-10 17:21:45 +02003240#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003241static int stac92xx_resume(struct hda_codec *codec)
3242{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003243 struct sigmatel_spec *spec = codec->spec;
3244
Richard Fish11b44bb2006-08-23 18:31:34 +02003245 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003246 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003247 stac_gpio_set(codec, spec->gpio_mask,
3248 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003249 snd_hda_codec_resume_amp(codec);
3250 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003251 /* power down inactive DACs */
3252 if (spec->dac_list)
3253 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003254 /* invoke unsolicited event to reset the HP state */
3255 if (spec->hp_detect)
3256 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003257 return 0;
3258}
3259#endif
3260
Matt2f2f4252005-04-13 14:45:30 +02003261static struct hda_codec_ops stac92xx_patch_ops = {
3262 .build_controls = stac92xx_build_controls,
3263 .build_pcms = stac92xx_build_pcms,
3264 .init = stac92xx_init,
3265 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003266 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003267#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003268 .resume = stac92xx_resume,
3269#endif
Matt2f2f4252005-04-13 14:45:30 +02003270};
3271
3272static int patch_stac9200(struct hda_codec *codec)
3273{
3274 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003275 int err;
Matt2f2f4252005-04-13 14:45:30 +02003276
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003277 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003278 if (spec == NULL)
3279 return -ENOMEM;
3280
3281 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003282 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003283 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003284 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3285 stac9200_models,
3286 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003287 if (spec->board_config < 0) {
3288 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3289 err = stac92xx_save_bios_config_regs(codec);
3290 if (err < 0) {
3291 stac92xx_free(codec);
3292 return err;
3293 }
3294 spec->pin_configs = spec->bios_pin_configs;
3295 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003296 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3297 stac92xx_set_config_regs(codec);
3298 }
Matt2f2f4252005-04-13 14:45:30 +02003299
3300 spec->multiout.max_channels = 2;
3301 spec->multiout.num_dacs = 1;
3302 spec->multiout.dac_nids = stac9200_dac_nids;
3303 spec->adc_nids = stac9200_adc_nids;
3304 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003305 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003306 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003307 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003308 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003309
Tobin Davisbf277782008-02-03 20:31:47 +01003310 if (spec->board_config == STAC_9200_GATEWAY ||
3311 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003312 spec->init = stac9200_eapd_init;
3313 else
3314 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003315 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003316
Takashi Iwai117f2572008-03-18 09:53:23 +01003317 if (spec->board_config == STAC_9200_PANASONIC) {
3318 spec->gpio_mask = spec->gpio_dir = 0x09;
3319 spec->gpio_data = 0x00;
3320 }
3321
Mattc7d4b2f2005-06-27 14:59:41 +02003322 err = stac9200_parse_auto_config(codec);
3323 if (err < 0) {
3324 stac92xx_free(codec);
3325 return err;
3326 }
Matt2f2f4252005-04-13 14:45:30 +02003327
3328 codec->patch_ops = stac92xx_patch_ops;
3329
3330 return 0;
3331}
3332
Tobin Davis8e21c342007-01-08 11:04:17 +01003333static int patch_stac925x(struct hda_codec *codec)
3334{
3335 struct sigmatel_spec *spec;
3336 int err;
3337
3338 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3339 if (spec == NULL)
3340 return -ENOMEM;
3341
3342 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003343 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003344 spec->pin_nids = stac925x_pin_nids;
3345 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3346 stac925x_models,
3347 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003348 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003349 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003350 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3351 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003352 err = stac92xx_save_bios_config_regs(codec);
3353 if (err < 0) {
3354 stac92xx_free(codec);
3355 return err;
3356 }
3357 spec->pin_configs = spec->bios_pin_configs;
3358 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3359 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3360 stac92xx_set_config_regs(codec);
3361 }
3362
3363 spec->multiout.max_channels = 2;
3364 spec->multiout.num_dacs = 1;
3365 spec->multiout.dac_nids = stac925x_dac_nids;
3366 spec->adc_nids = stac925x_adc_nids;
3367 spec->mux_nids = stac925x_mux_nids;
3368 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003369 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003370 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02003371 switch (codec->vendor_id) {
3372 case 0x83847632: /* STAC9202 */
3373 case 0x83847633: /* STAC9202D */
3374 case 0x83847636: /* STAC9251 */
3375 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02003376 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02003377 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003378 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
3379 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02003380 break;
3381 default:
3382 spec->num_dmics = 0;
3383 break;
3384 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003385
3386 spec->init = stac925x_core_init;
3387 spec->mixer = stac925x_mixer;
3388
3389 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003390 if (!err) {
3391 if (spec->board_config < 0) {
3392 printk(KERN_WARNING "hda_codec: No auto-config is "
3393 "available, default to model=ref\n");
3394 spec->board_config = STAC_925x_REF;
3395 goto again;
3396 }
3397 err = -EINVAL;
3398 }
Tobin Davis8e21c342007-01-08 11:04:17 +01003399 if (err < 0) {
3400 stac92xx_free(codec);
3401 return err;
3402 }
3403
3404 codec->patch_ops = stac92xx_patch_ops;
3405
3406 return 0;
3407}
3408
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003409static struct hda_input_mux stac92hd73xx_dmux = {
3410 .num_items = 4,
3411 .items = {
3412 { "Analog Inputs", 0x0b },
3413 { "CD", 0x08 },
3414 { "Digital Mic 1", 0x09 },
3415 { "Digital Mic 2", 0x0a },
3416 }
3417};
3418
3419static int patch_stac92hd73xx(struct hda_codec *codec)
3420{
3421 struct sigmatel_spec *spec;
3422 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
3423 int err = 0;
3424
3425 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3426 if (spec == NULL)
3427 return -ENOMEM;
3428
3429 codec->spec = spec;
3430 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
3431 spec->pin_nids = stac92hd73xx_pin_nids;
3432 spec->board_config = snd_hda_check_board_config(codec,
3433 STAC_92HD73XX_MODELS,
3434 stac92hd73xx_models,
3435 stac92hd73xx_cfg_tbl);
3436again:
3437 if (spec->board_config < 0) {
3438 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3439 " STAC92HD73XX, using BIOS defaults\n");
3440 err = stac92xx_save_bios_config_regs(codec);
3441 if (err < 0) {
3442 stac92xx_free(codec);
3443 return err;
3444 }
3445 spec->pin_configs = spec->bios_pin_configs;
3446 } else {
3447 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
3448 stac92xx_set_config_regs(codec);
3449 }
3450
3451 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
3452 conn, STAC92HD73_DAC_COUNT + 2) - 1;
3453
3454 if (spec->multiout.num_dacs < 0) {
3455 printk(KERN_WARNING "hda_codec: Could not determine "
3456 "number of channels defaulting to DAC count\n");
3457 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
3458 }
3459
3460 switch (spec->multiout.num_dacs) {
3461 case 0x3: /* 6 Channel */
3462 spec->mixer = stac92hd73xx_6ch_mixer;
3463 spec->init = stac92hd73xx_6ch_core_init;
3464 break;
3465 case 0x4: /* 8 Channel */
3466 spec->multiout.hp_nid = 0x18;
3467 spec->mixer = stac92hd73xx_8ch_mixer;
3468 spec->init = stac92hd73xx_8ch_core_init;
3469 break;
3470 case 0x5: /* 10 Channel */
3471 spec->multiout.hp_nid = 0x19;
3472 spec->mixer = stac92hd73xx_10ch_mixer;
3473 spec->init = stac92hd73xx_10ch_core_init;
3474 };
3475
3476 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
3477 spec->aloopback_mask = 0x01;
3478 spec->aloopback_shift = 8;
3479
3480 spec->mux_nids = stac92hd73xx_mux_nids;
3481 spec->adc_nids = stac92hd73xx_adc_nids;
3482 spec->dmic_nids = stac92hd73xx_dmic_nids;
3483 spec->dmux_nids = stac92hd73xx_dmux_nids;
3484
3485 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
3486 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01003487 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003488 spec->dinput_mux = &stac92hd73xx_dmux;
3489 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003490 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003491 spec->gpio_data = 0x01;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003492
Matthew Ranostaya7662642008-02-21 07:51:14 +01003493 switch (spec->board_config) {
3494 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003495 spec->init = dell_eq_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01003496 switch (codec->subsystem_id) {
3497 case 0x1028025e: /* Analog Mics */
3498 case 0x1028025f:
3499 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3500 spec->num_dmics = 0;
3501 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01003502 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01003503 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01003504 spec->init = dell_m6_core_init;
3505 /* fall-through */
3506 case 0x10280254:
3507 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01003508 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3509 spec->num_dmics = 1;
3510 break;
3511 case 0x10280256: /* Both */
3512 case 0x10280057:
3513 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
3514 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
3515 spec->num_dmics = 1;
3516 break;
3517 }
3518 break;
3519 default:
3520 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
3521 }
3522
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003523 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
3524 spec->pwr_nids = stac92hd73xx_pwr_nids;
3525
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003526 err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
3527
3528 if (!err) {
3529 if (spec->board_config < 0) {
3530 printk(KERN_WARNING "hda_codec: No auto-config is "
3531 "available, default to model=ref\n");
3532 spec->board_config = STAC_92HD73XX_REF;
3533 goto again;
3534 }
3535 err = -EINVAL;
3536 }
3537
3538 if (err < 0) {
3539 stac92xx_free(codec);
3540 return err;
3541 }
3542
3543 codec->patch_ops = stac92xx_patch_ops;
3544
3545 return 0;
3546}
3547
Matthew Ranostaye035b842007-11-06 11:53:55 +01003548static int patch_stac92hd71bxx(struct hda_codec *codec)
3549{
3550 struct sigmatel_spec *spec;
3551 int err = 0;
3552
3553 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3554 if (spec == NULL)
3555 return -ENOMEM;
3556
3557 codec->spec = spec;
3558 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
3559 spec->pin_nids = stac92hd71bxx_pin_nids;
3560 spec->board_config = snd_hda_check_board_config(codec,
3561 STAC_92HD71BXX_MODELS,
3562 stac92hd71bxx_models,
3563 stac92hd71bxx_cfg_tbl);
3564again:
3565 if (spec->board_config < 0) {
3566 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3567 " STAC92HD71BXX, using BIOS defaults\n");
3568 err = stac92xx_save_bios_config_regs(codec);
3569 if (err < 0) {
3570 stac92xx_free(codec);
3571 return err;
3572 }
3573 spec->pin_configs = spec->bios_pin_configs;
3574 } else {
3575 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
3576 stac92xx_set_config_regs(codec);
3577 }
3578
Matthew Ranostay541eee82007-12-14 12:08:04 +01003579 switch (codec->vendor_id) {
3580 case 0x111d76b6: /* 4 Port without Analog Mixer */
3581 case 0x111d76b7:
3582 case 0x111d76b4: /* 6 Port without Analog Mixer */
3583 case 0x111d76b5:
3584 spec->mixer = stac92hd71bxx_mixer;
3585 spec->init = stac92hd71bxx_core_init;
3586 break;
3587 default:
3588 spec->mixer = stac92hd71bxx_analog_mixer;
3589 spec->init = stac92hd71bxx_analog_core_init;
3590 }
3591
3592 spec->aloopback_mask = 0x20;
3593 spec->aloopback_shift = 0;
3594
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003595 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003596 spec->gpio_mask = 0x01;
3597 spec->gpio_dir = 0x01;
3598 spec->gpio_mask = 0x01;
3599 spec->gpio_data = 0x01;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003600
Matthew Ranostaye035b842007-11-06 11:53:55 +01003601 spec->mux_nids = stac92hd71bxx_mux_nids;
3602 spec->adc_nids = stac92hd71bxx_adc_nids;
3603 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003604 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003605
3606 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
3607 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
3608 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003609 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01003610
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003611 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
3612 spec->pwr_nids = stac92hd71bxx_pwr_nids;
3613
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01003614 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01003615 spec->multiout.hp_nid = 0x11;
3616 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
3617
3618 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
3619 if (!err) {
3620 if (spec->board_config < 0) {
3621 printk(KERN_WARNING "hda_codec: No auto-config is "
3622 "available, default to model=ref\n");
3623 spec->board_config = STAC_92HD71BXX_REF;
3624 goto again;
3625 }
3626 err = -EINVAL;
3627 }
3628
3629 if (err < 0) {
3630 stac92xx_free(codec);
3631 return err;
3632 }
3633
3634 codec->patch_ops = stac92xx_patch_ops;
3635
3636 return 0;
3637};
3638
Matt2f2f4252005-04-13 14:45:30 +02003639static int patch_stac922x(struct hda_codec *codec)
3640{
3641 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003642 int err;
Matt2f2f4252005-04-13 14:45:30 +02003643
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003644 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003645 if (spec == NULL)
3646 return -ENOMEM;
3647
3648 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003649 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003650 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003651 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
3652 stac922x_models,
3653 stac922x_cfg_tbl);
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003654 if (spec->board_config == STAC_INTEL_MAC_V3) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003655 spec->gpio_mask = spec->gpio_dir = 0x03;
3656 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003657 /* Intel Macs have all same PCI SSID, so we need to check
3658 * codec SSID to distinguish the exact models
3659 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003660 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003661 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003662
3663 case 0x106b0800:
3664 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02003665 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003666 case 0x106b0600:
3667 case 0x106b0700:
3668 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01003669 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003670 case 0x106b0e00:
3671 case 0x106b0f00:
3672 case 0x106b1600:
3673 case 0x106b1700:
3674 case 0x106b0200:
3675 case 0x106b1e00:
3676 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003677 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003678 case 0x106b1a00:
3679 case 0x00000100:
3680 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02003681 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02003682 case 0x106b0a00:
3683 case 0x106b2200:
3684 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02003685 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01003686 }
3687 }
3688
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003689 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003690 if (spec->board_config < 0) {
3691 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
3692 "using BIOS defaults\n");
3693 err = stac92xx_save_bios_config_regs(codec);
3694 if (err < 0) {
3695 stac92xx_free(codec);
3696 return err;
3697 }
3698 spec->pin_configs = spec->bios_pin_configs;
3699 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01003700 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
3701 stac92xx_set_config_regs(codec);
3702 }
Matt2f2f4252005-04-13 14:45:30 +02003703
Matt2f2f4252005-04-13 14:45:30 +02003704 spec->adc_nids = stac922x_adc_nids;
3705 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003706 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003707 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003708 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003709 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003710
3711 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003712 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003713
3714 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003715
Matt Porter3cc08dc2006-01-23 15:27:49 +01003716 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003717 if (!err) {
3718 if (spec->board_config < 0) {
3719 printk(KERN_WARNING "hda_codec: No auto-config is "
3720 "available, default to model=ref\n");
3721 spec->board_config = STAC_D945_REF;
3722 goto again;
3723 }
3724 err = -EINVAL;
3725 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003726 if (err < 0) {
3727 stac92xx_free(codec);
3728 return err;
3729 }
3730
3731 codec->patch_ops = stac92xx_patch_ops;
3732
Takashi Iwai807a46362007-05-29 19:01:37 +02003733 /* Fix Mux capture level; max to 2 */
3734 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
3735 (0 << AC_AMPCAP_OFFSET_SHIFT) |
3736 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3737 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3738 (0 << AC_AMPCAP_MUTE_SHIFT));
3739
Matt Porter3cc08dc2006-01-23 15:27:49 +01003740 return 0;
3741}
3742
3743static int patch_stac927x(struct hda_codec *codec)
3744{
3745 struct sigmatel_spec *spec;
3746 int err;
3747
3748 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3749 if (spec == NULL)
3750 return -ENOMEM;
3751
3752 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003753 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003754 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003755 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
3756 stac927x_models,
3757 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003758 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003759 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
3760 if (spec->board_config < 0)
3761 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
3762 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02003763 err = stac92xx_save_bios_config_regs(codec);
3764 if (err < 0) {
3765 stac92xx_free(codec);
3766 return err;
3767 }
3768 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003769 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003770 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
3771 stac92xx_set_config_regs(codec);
3772 }
3773
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003774 spec->adc_nids = stac927x_adc_nids;
3775 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
3776 spec->mux_nids = stac927x_mux_nids;
3777 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003778 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003779 spec->multiout.dac_nids = spec->dac_nids;
3780
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003781 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02003782 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003783 case STAC_D965_5ST:
3784 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003785 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003786 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003787 spec->num_dmics = 0;
3788
Tobin Davis93ed1502006-09-01 21:03:12 +02003789 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003790 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003791 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003792 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02003793 switch (codec->subsystem_id) {
3794 case 0x10280209:
3795 case 0x1028022e:
3796 /* correct the device field to SPDIF out */
3797 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
3798 break;
3799 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01003800 /* configure the analog microphone on some laptops */
3801 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01003802 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01003803 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01003804 /* correct the front input jack as a mic */
3805 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
3806 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003807 case STAC_DELL_3ST:
3808 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003809 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003810 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003811 spec->dmic_nids = stac927x_dmic_nids;
3812 spec->num_dmics = STAC927X_NUM_DMICS;
3813
Tobin Davis93ed1502006-09-01 21:03:12 +02003814 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003815 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003816 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003817 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003818 break;
3819 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003820 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003821 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003822 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003823 spec->num_dmics = 0;
3824
Tobin Davis81d3dbd2006-08-22 19:44:45 +02003825 spec->init = stac927x_core_init;
3826 spec->mixer = stac927x_mixer;
3827 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01003828
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003829 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003830 spec->aloopback_mask = 0x40;
3831 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003832
Matt Porter3cc08dc2006-01-23 15:27:49 +01003833 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003834 if (!err) {
3835 if (spec->board_config < 0) {
3836 printk(KERN_WARNING "hda_codec: No auto-config is "
3837 "available, default to model=ref\n");
3838 spec->board_config = STAC_D965_REF;
3839 goto again;
3840 }
3841 err = -EINVAL;
3842 }
Mattc7d4b2f2005-06-27 14:59:41 +02003843 if (err < 0) {
3844 stac92xx_free(codec);
3845 return err;
3846 }
Matt2f2f4252005-04-13 14:45:30 +02003847
3848 codec->patch_ops = stac92xx_patch_ops;
3849
Takashi Iwai52987652008-01-16 16:09:47 +01003850 /*
3851 * !!FIXME!!
3852 * The STAC927x seem to require fairly long delays for certain
3853 * command sequences. With too short delays (even if the answer
3854 * is set to RIRB properly), it results in the silence output
3855 * on some hardwares like Dell.
3856 *
3857 * The below flag enables the longer delay (see get_response
3858 * in hda_intel.c).
3859 */
3860 codec->bus->needs_damn_long_delay = 1;
3861
Matt2f2f4252005-04-13 14:45:30 +02003862 return 0;
3863}
3864
Matt Porterf3302a52006-07-31 12:49:34 +02003865static int patch_stac9205(struct hda_codec *codec)
3866{
3867 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02003868 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02003869
3870 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3871 if (spec == NULL)
3872 return -ENOMEM;
3873
3874 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003875 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003876 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003877 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
3878 stac9205_models,
3879 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003880 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02003881 if (spec->board_config < 0) {
3882 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
3883 err = stac92xx_save_bios_config_regs(codec);
3884 if (err < 0) {
3885 stac92xx_free(codec);
3886 return err;
3887 }
3888 spec->pin_configs = spec->bios_pin_configs;
3889 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02003890 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
3891 stac92xx_set_config_regs(codec);
3892 }
3893
3894 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003895 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02003896 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01003897 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02003898 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02003899 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003900 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01003901 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003902 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003903
3904 spec->init = stac9205_core_init;
3905 spec->mixer = stac9205_mixer;
3906
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003907 spec->aloopback_mask = 0x40;
3908 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02003909 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02003910
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003911 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003912 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02003913 /* Enable SPDIF in/out */
3914 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
3915 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01003916
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003917 /* Enable unsol response for GPIO4/Dock HP connection */
3918 snd_hda_codec_write(codec, codec->afg, 0,
3919 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
3920 snd_hda_codec_write_cache(codec, codec->afg, 0,
3921 AC_VERB_SET_UNSOLICITED_ENABLE,
3922 (AC_USRSP_EN | STAC_HP_EVENT));
3923
3924 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003925 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003926 spec->gpio_mask = 0x1b;
3927 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01003928 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003929 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02003930 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003931 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003932 break;
3933 default:
3934 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003935 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003936 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02003937 break;
3938 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02003939
Matt Porterf3302a52006-07-31 12:49:34 +02003940 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003941 if (!err) {
3942 if (spec->board_config < 0) {
3943 printk(KERN_WARNING "hda_codec: No auto-config is "
3944 "available, default to model=ref\n");
3945 spec->board_config = STAC_9205_REF;
3946 goto again;
3947 }
3948 err = -EINVAL;
3949 }
Matt Porterf3302a52006-07-31 12:49:34 +02003950 if (err < 0) {
3951 stac92xx_free(codec);
3952 return err;
3953 }
3954
3955 codec->patch_ops = stac92xx_patch_ops;
3956
3957 return 0;
3958}
3959
Matt2f2f4252005-04-13 14:45:30 +02003960/*
Guillaume Munch6d859062006-08-22 17:15:47 +02003961 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01003962 */
3963
Guillaume Munch99ccc562006-08-16 19:35:12 +02003964/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003965static hda_nid_t vaio_dacs[] = { 0x2 };
3966#define VAIO_HP_DAC 0x5
3967static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
3968static hda_nid_t vaio_mux_nids[] = { 0x15 };
3969
3970static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02003971 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01003972 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02003973 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003974 { "Mic Jack", 0x1 },
3975 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01003976 { "PCM", 0x3 },
3977 }
3978};
3979
3980static struct hda_verb vaio_init[] = {
3981 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02003982 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01003983 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3984 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
3985 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
3986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02003987 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01003988 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
3989 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
3990 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
3991 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
3992 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
3993 {}
3994};
3995
Guillaume Munch6d859062006-08-22 17:15:47 +02003996static struct hda_verb vaio_ar_init[] = {
3997 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
3998 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
3999 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4000 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4001/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4002 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004003 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004004 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4005 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4006/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4007 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4008 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4009 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4010 {}
4011};
4012
Takashi Iwaidb064e52006-03-16 16:04:58 +01004013/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004014static struct hda_bind_ctls vaio_bind_master_vol = {
4015 .ops = &snd_hda_bind_vol,
4016 .values = {
4017 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4018 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4019 0
4020 },
4021};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004022
4023/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004024static struct hda_bind_ctls vaio_bind_master_sw = {
4025 .ops = &snd_hda_bind_sw,
4026 .values = {
4027 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4028 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4029 0,
4030 },
4031};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004032
4033static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004034 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4035 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004036 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4037 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4038 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4039 {
4040 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4041 .name = "Capture Source",
4042 .count = 1,
4043 .info = stac92xx_mux_enum_info,
4044 .get = stac92xx_mux_enum_get,
4045 .put = stac92xx_mux_enum_put,
4046 },
4047 {}
4048};
4049
Guillaume Munch6d859062006-08-22 17:15:47 +02004050static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004051 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4052 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004053 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4054 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4055 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4056 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4057 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4058 {
4059 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4060 .name = "Capture Source",
4061 .count = 1,
4062 .info = stac92xx_mux_enum_info,
4063 .get = stac92xx_mux_enum_get,
4064 .put = stac92xx_mux_enum_put,
4065 },
4066 {}
4067};
4068
4069static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004070 .build_controls = stac92xx_build_controls,
4071 .build_pcms = stac92xx_build_pcms,
4072 .init = stac92xx_init,
4073 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004074#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004075 .resume = stac92xx_resume,
4076#endif
4077};
4078
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004079static int stac9872_vaio_init(struct hda_codec *codec)
4080{
4081 int err;
4082
4083 err = stac92xx_init(codec);
4084 if (err < 0)
4085 return err;
4086 if (codec->patch_ops.unsol_event)
4087 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4088 return 0;
4089}
4090
4091static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4092{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004093 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004094 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4095 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4096 } else {
4097 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4098 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4099 }
4100}
4101
4102static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4103{
4104 switch (res >> 26) {
4105 case STAC_HP_EVENT:
4106 stac9872_vaio_hp_detect(codec, res);
4107 break;
4108 }
4109}
4110
4111static struct hda_codec_ops stac9872_vaio_patch_ops = {
4112 .build_controls = stac92xx_build_controls,
4113 .build_pcms = stac92xx_build_pcms,
4114 .init = stac9872_vaio_init,
4115 .free = stac92xx_free,
4116 .unsol_event = stac9872_vaio_unsol_event,
4117#ifdef CONFIG_PM
4118 .resume = stac92xx_resume,
4119#endif
4120};
4121
Guillaume Munch6d859062006-08-22 17:15:47 +02004122enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4123 CXD9872RD_VAIO,
4124 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4125 STAC9872AK_VAIO,
4126 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4127 STAC9872K_VAIO,
4128 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004129 CXD9872AKD_VAIO,
4130 STAC_9872_MODELS,
4131};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004132
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004133static const char *stac9872_models[STAC_9872_MODELS] = {
4134 [CXD9872RD_VAIO] = "vaio",
4135 [CXD9872AKD_VAIO] = "vaio-ar",
4136};
4137
4138static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4139 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4140 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4141 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004142 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004143 {}
4144};
4145
Guillaume Munch6d859062006-08-22 17:15:47 +02004146static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01004147{
4148 struct sigmatel_spec *spec;
4149 int board_config;
4150
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004151 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
4152 stac9872_models,
4153 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01004154 if (board_config < 0)
4155 /* unknown config, let generic-parser do its job... */
4156 return snd_hda_parse_generic_codec(codec);
4157
4158 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4159 if (spec == NULL)
4160 return -ENOMEM;
4161
4162 codec->spec = spec;
4163 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02004164 case CXD9872RD_VAIO:
4165 case STAC9872AK_VAIO:
4166 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01004167 spec->mixer = vaio_mixer;
4168 spec->init = vaio_init;
4169 spec->multiout.max_channels = 2;
4170 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4171 spec->multiout.dac_nids = vaio_dacs;
4172 spec->multiout.hp_nid = VAIO_HP_DAC;
4173 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
4174 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004175 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004176 spec->input_mux = &vaio_mux;
4177 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004178 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004179 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02004180
4181 case CXD9872AKD_VAIO:
4182 spec->mixer = vaio_ar_mixer;
4183 spec->init = vaio_ar_init;
4184 spec->multiout.max_channels = 2;
4185 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
4186 spec->multiout.dac_nids = vaio_dacs;
4187 spec->multiout.hp_nid = VAIO_HP_DAC;
4188 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004189 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02004190 spec->adc_nids = vaio_adcs;
4191 spec->input_mux = &vaio_mux;
4192 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004193 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02004194 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01004195 }
4196
Takashi Iwaidb064e52006-03-16 16:04:58 +01004197 return 0;
4198}
4199
4200
4201/*
Matt2f2f4252005-04-13 14:45:30 +02004202 * patch entries
4203 */
4204struct hda_codec_preset snd_hda_preset_sigmatel[] = {
4205 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
4206 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
4207 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
4208 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
4209 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
4210 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
4211 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02004212 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
4213 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
4214 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
4215 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
4216 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
4217 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01004218 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
4219 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
4220 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
4221 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
4222 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
4223 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
4224 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
4225 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
4226 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
4227 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01004228 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
4229 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
4230 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
4231 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
4232 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
4233 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Guillaume Munch6d859062006-08-22 17:15:47 +02004234 /* The following does not take into account .id=0x83847661 when subsys =
4235 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
4236 * currently not fully supported.
4237 */
4238 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
4239 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
4240 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02004241 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
4242 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
4243 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
4244 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
4245 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
4246 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
4247 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
4248 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004249 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
4250 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004251 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01004252 { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
4253 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4254 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
4255 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4256 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
4257 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4258 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
4259 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
4260 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02004261 {} /* terminator */
4262};