blob: 66c12d3e9c7947021e40fbc1235b14b77e5de712 [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>
Matthew Ranostay45a6ac12008-10-15 14:45:38 -040033#include <sound/jack.h>
Matt2f2f4252005-04-13 14:45:30 +020034#include "hda_codec.h"
35#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010036#include "hda_patch.h"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020037#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020038
Matthew Ranostay74aeaab2008-10-25 01:06:04 -040039#define STAC_INSERT_EVENT 0x10
Matthew Ranostaya64135a2008-01-10 16:55:06 +010040#define STAC_PWR_EVENT 0x20
41#define STAC_HP_EVENT 0x30
Matthew Ranostay72474be2008-10-09 09:32:17 -040042#define STAC_VREF_EVENT 0x40
Matt4e550962005-07-04 17:51:39 +020043
Takashi Iwaif5fcc132006-11-24 17:07:44 +010044enum {
45 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010046 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020047 STAC_9200_DELL_D21,
48 STAC_9200_DELL_D22,
49 STAC_9200_DELL_D23,
50 STAC_9200_DELL_M21,
51 STAC_9200_DELL_M22,
52 STAC_9200_DELL_M23,
53 STAC_9200_DELL_M24,
54 STAC_9200_DELL_M25,
55 STAC_9200_DELL_M26,
56 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020057 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010058 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010059 STAC_9200_MODELS
60};
61
62enum {
63 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020064 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020065 STAC_9205_DELL_M43,
66 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010067 STAC_9205_MODELS
68};
69
70enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010071 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010072 STAC_DELL_M6,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -050073 STAC_DELL_EQ,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010074 STAC_92HD73XX_MODELS
75};
76
77enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020078 STAC_92HD83XXX_REF,
79 STAC_92HD83XXX_MODELS
80};
81
82enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010083 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010084 STAC_DELL_M4_1,
85 STAC_DELL_M4_2,
Matthew Ranostay6a14f582008-09-12 12:02:30 -040086 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010087 STAC_92HD71BXX_MODELS
88};
89
90enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010091 STAC_925x_REF,
92 STAC_M2_2,
93 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020094 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010095 STAC_925x_MODELS
96};
97
98enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010099 STAC_D945_REF,
100 STAC_D945GTP3,
101 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200102 STAC_INTEL_MAC_V1,
103 STAC_INTEL_MAC_V2,
104 STAC_INTEL_MAC_V3,
105 STAC_INTEL_MAC_V4,
106 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800107 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
108 * is given, one of the above models will be
109 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200110 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100111 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100112 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100113 STAC_MACBOOK_PRO_V1,
114 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200115 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200116 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300117 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200118 STAC_922X_DELL_D81,
119 STAC_922X_DELL_D82,
120 STAC_922X_DELL_M81,
121 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100122 STAC_922X_MODELS
123};
124
125enum {
126 STAC_D965_REF,
127 STAC_D965_3ST,
128 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200129 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100130 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100131 STAC_927X_MODELS
132};
Matt Porter403d1942005-11-29 15:00:51 +0100133
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400134struct sigmatel_event {
135 hda_nid_t nid;
136 int data;
137};
138
139struct sigmatel_jack {
140 hda_nid_t nid;
141 int type;
142 struct snd_jack *jack;
143};
144
Matt2f2f4252005-04-13 14:45:30 +0200145struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100146 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200147 unsigned int num_mixers;
148
Matt Porter403d1942005-11-29 15:00:51 +0100149 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200150 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100151 unsigned int line_switch: 1;
152 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100153 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100154 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400155 unsigned int spdif_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200156
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100157 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200158 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100159 unsigned int gpio_mask;
160 unsigned int gpio_dir;
161 unsigned int gpio_data;
162 unsigned int gpio_mute;
163
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200164 /* stream */
165 unsigned int stream_delay;
166
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100167 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100168 unsigned char aloopback_mask;
169 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200170
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100171 /* power management */
172 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200173 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100174 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100175 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100176
Matthew Ranostay74aeaab2008-10-25 01:06:04 -0400177 /* jack detection */
178 struct snd_array jacks;
179
180 /* events */
181 struct snd_array events;
182
Matt2f2f4252005-04-13 14:45:30 +0200183 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100184 struct hda_input_mux *mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400185 struct hda_input_mux *amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100186 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200187 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100188 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200189
190 /* capture */
191 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200192 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200193 hda_nid_t *mux_nids;
194 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200195 hda_nid_t *dmic_nids;
196 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100197 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100198 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200199 hda_nid_t *smux_nids;
200 unsigned int num_smuxes;
Matthew Ranostay65973632008-09-16 10:39:37 -0400201 const char **spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200202
Mattdabbed62005-06-14 10:19:34 +0200203 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100204 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200205 hda_nid_t anabeep_nid;
206 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200207
Matt2f2f4252005-04-13 14:45:30 +0200208 /* pin widgets */
209 hda_nid_t *pin_nids;
210 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200211 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200212 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200213
214 /* codec specific stuff */
215 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100216 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200217
218 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200219 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100220 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200221 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100222 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200223 struct hda_input_mux *sinput_mux;
224 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400225 unsigned int cur_amux;
226 hda_nid_t *amp_nids;
227 unsigned int num_amps;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200228 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200229
Matt Porter403d1942005-11-29 15:00:51 +0100230 /* i/o switches */
231 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200232 unsigned int clfe_swap;
Takashi Iwaid7a89432008-11-12 09:48:04 +0100233 unsigned int hp_switch; /* NID of HP as line-out */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200234 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200235
Mattc7d4b2f2005-06-27 14:59:41 +0200236 struct hda_pcm pcm_rec[2]; /* PCM information */
237
238 /* dynamic controls and input_mux */
239 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200240 struct snd_array kctls;
Matt Porter8b657272006-10-26 17:12:59 +0200241 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200242 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200243 struct hda_input_mux private_smux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400244 struct hda_input_mux private_amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100245 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200246};
247
248static hda_nid_t stac9200_adc_nids[1] = {
249 0x03,
250};
251
252static hda_nid_t stac9200_mux_nids[1] = {
253 0x0c,
254};
255
256static hda_nid_t stac9200_dac_nids[1] = {
257 0x02,
258};
259
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100260static hda_nid_t stac92hd73xx_pwr_nids[8] = {
261 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
262 0x0f, 0x10, 0x11
263};
264
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400265static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
266 0x26, 0,
267};
268
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100269static hda_nid_t stac92hd73xx_adc_nids[2] = {
270 0x1a, 0x1b
271};
272
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400273#define DELL_M6_AMP 2
274static hda_nid_t stac92hd73xx_amp_nids[3] = {
275 0x0b, 0x0c, 0x0e
Matthew Ranostay89385032008-09-11 09:49:39 -0400276};
277
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100278#define STAC92HD73XX_NUM_DMICS 2
279static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
280 0x13, 0x14, 0
281};
282
283#define STAC92HD73_DAC_COUNT 5
284static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
285 0x15, 0x16, 0x17, 0x18, 0x19,
286};
287
288static hda_nid_t stac92hd73xx_mux_nids[4] = {
289 0x28, 0x29, 0x2a, 0x2b,
290};
291
292static hda_nid_t stac92hd73xx_dmux_nids[2] = {
293 0x20, 0x21,
294};
295
Matthew Ranostayd9737752008-09-07 12:03:41 +0200296static hda_nid_t stac92hd73xx_smux_nids[2] = {
297 0x22, 0x23,
298};
299
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200300#define STAC92HD83XXX_NUM_DMICS 2
301static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
302 0x11, 0x12, 0
303};
304
305#define STAC92HD81_DAC_COUNT 2
306#define STAC92HD83_DAC_COUNT 3
307static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
308 0x13, 0x14, 0x22,
309};
310
311static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
312 0x17, 0x18,
313};
314
315static hda_nid_t stac92hd83xxx_adc_nids[2] = {
316 0x15, 0x16,
317};
318
319static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
320 0xa, 0xb, 0xd, 0xe,
321};
322
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400323static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
324 0x1e, 0,
325};
326
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200327static unsigned int stac92hd83xxx_pwr_mapping[4] = {
328 0x03, 0x0c, 0x10, 0x40,
329};
330
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100331static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
332 0x0a, 0x0d, 0x0f
333};
334
Matthew Ranostaye035b842007-11-06 11:53:55 +0100335static hda_nid_t stac92hd71bxx_adc_nids[2] = {
336 0x12, 0x13,
337};
338
339static hda_nid_t stac92hd71bxx_mux_nids[2] = {
340 0x1a, 0x1b
341};
342
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400343static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
344 0x1c, 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100345};
346
Matthew Ranostayd9737752008-09-07 12:03:41 +0200347static hda_nid_t stac92hd71bxx_smux_nids[2] = {
348 0x24, 0x25,
349};
350
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100351static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100352 0x10, /*0x11, */
353};
354
355#define STAC92HD71BXX_NUM_DMICS 2
356static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
357 0x18, 0x19, 0
358};
359
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400360static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
361 0x22, 0
362};
363
Tobin Davis8e21c342007-01-08 11:04:17 +0100364static hda_nid_t stac925x_adc_nids[1] = {
365 0x03,
366};
367
368static hda_nid_t stac925x_mux_nids[1] = {
369 0x0f,
370};
371
372static hda_nid_t stac925x_dac_nids[1] = {
373 0x02,
374};
375
Takashi Iwaif6e98522007-10-16 14:27:04 +0200376#define STAC925X_NUM_DMICS 1
377static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
378 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200379};
380
Takashi Iwai1697055e2007-12-18 18:05:52 +0100381static hda_nid_t stac925x_dmux_nids[1] = {
382 0x14,
383};
384
Matt2f2f4252005-04-13 14:45:30 +0200385static hda_nid_t stac922x_adc_nids[2] = {
386 0x06, 0x07,
387};
388
389static hda_nid_t stac922x_mux_nids[2] = {
390 0x12, 0x13,
391};
392
Matt Porter3cc08dc2006-01-23 15:27:49 +0100393static hda_nid_t stac927x_adc_nids[3] = {
394 0x07, 0x08, 0x09
395};
396
397static hda_nid_t stac927x_mux_nids[3] = {
398 0x15, 0x16, 0x17
399};
400
Matthew Ranostayd9737752008-09-07 12:03:41 +0200401static hda_nid_t stac927x_smux_nids[1] = {
402 0x21,
403};
404
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100405static hda_nid_t stac927x_dac_nids[6] = {
406 0x02, 0x03, 0x04, 0x05, 0x06, 0
407};
408
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100409static hda_nid_t stac927x_dmux_nids[1] = {
410 0x1b,
411};
412
Matthew Ranostay7f168592007-10-18 17:38:17 +0200413#define STAC927X_NUM_DMICS 2
414static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
415 0x13, 0x14, 0
416};
417
Matthew Ranostay65973632008-09-16 10:39:37 -0400418static const char *stac927x_spdif_labels[5] = {
419 "Digital Playback", "ADAT", "Analog Mux 1",
420 "Analog Mux 2", "Analog Mux 3"
421};
422
Matt Porterf3302a52006-07-31 12:49:34 +0200423static hda_nid_t stac9205_adc_nids[2] = {
424 0x12, 0x13
425};
426
427static hda_nid_t stac9205_mux_nids[2] = {
428 0x19, 0x1a
429};
430
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100431static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100432 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100433};
434
Matthew Ranostayd9737752008-09-07 12:03:41 +0200435static hda_nid_t stac9205_smux_nids[1] = {
436 0x21,
437};
438
Takashi Iwaif6e98522007-10-16 14:27:04 +0200439#define STAC9205_NUM_DMICS 2
440static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
441 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200442};
443
Mattc7d4b2f2005-06-27 14:59:41 +0200444static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200445 0x08, 0x09, 0x0d, 0x0e,
446 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200447};
448
Tobin Davis8e21c342007-01-08 11:04:17 +0100449static hda_nid_t stac925x_pin_nids[8] = {
450 0x07, 0x08, 0x0a, 0x0b,
451 0x0c, 0x0d, 0x10, 0x11,
452};
453
Matt2f2f4252005-04-13 14:45:30 +0200454static hda_nid_t stac922x_pin_nids[10] = {
455 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
456 0x0f, 0x10, 0x11, 0x15, 0x1b,
457};
458
Matthew Ranostaya7662642008-02-21 07:51:14 +0100459static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100460 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
461 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200462 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100463};
464
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200465static hda_nid_t stac92hd83xxx_pin_nids[14] = {
466 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
467 0x0f, 0x10, 0x11, 0x12, 0x13,
468 0x1d, 0x1e, 0x1f, 0x20
469};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400470static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100471 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
472 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400473 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100474};
475
Matt Porter3cc08dc2006-01-23 15:27:49 +0100476static hda_nid_t stac927x_pin_nids[14] = {
477 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
478 0x0f, 0x10, 0x11, 0x12, 0x13,
479 0x14, 0x21, 0x22, 0x23,
480};
481
Matt Porterf3302a52006-07-31 12:49:34 +0200482static hda_nid_t stac9205_pin_nids[12] = {
483 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
484 0x0f, 0x14, 0x16, 0x17, 0x18,
485 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200486};
487
Matthew Ranostay89385032008-09-11 09:49:39 -0400488#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
489
490static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
491 struct snd_ctl_elem_value *ucontrol)
492{
493 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
494 struct sigmatel_spec *spec = codec->spec;
495 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
496
497 kcontrol->private_value ^= get_amp_nid(kcontrol);
498 kcontrol->private_value |= nid;
499
500 return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
501}
502
503static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
504 struct snd_ctl_elem_value *ucontrol)
505{
506 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
507 struct sigmatel_spec *spec = codec->spec;
508 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
509
510 kcontrol->private_value ^= get_amp_nid(kcontrol);
511 kcontrol->private_value |= nid;
512
513 return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
514}
515
Matt Porter8b657272006-10-26 17:12:59 +0200516static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_info *uinfo)
518{
519 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
520 struct sigmatel_spec *spec = codec->spec;
521 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
522}
523
524static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
525 struct snd_ctl_elem_value *ucontrol)
526{
527 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
528 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100529 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200530
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100531 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200532 return 0;
533}
534
535static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
536 struct snd_ctl_elem_value *ucontrol)
537{
538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
539 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100540 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200541
542 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100543 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200544}
545
Matthew Ranostayd9737752008-09-07 12:03:41 +0200546static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
547 struct snd_ctl_elem_info *uinfo)
548{
549 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
550 struct sigmatel_spec *spec = codec->spec;
551 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
552}
553
554static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
555 struct snd_ctl_elem_value *ucontrol)
556{
557 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
558 struct sigmatel_spec *spec = codec->spec;
559 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
560
561 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
562 return 0;
563}
564
565static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
566 struct snd_ctl_elem_value *ucontrol)
567{
568 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
569 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400570 struct hda_input_mux *smux = &spec->private_smux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200571 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400572 int err, val;
573 hda_nid_t nid;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200574
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400575 err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200576 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400577 if (err < 0)
578 return err;
579
580 if (spec->spdif_mute) {
581 if (smux_idx == 0)
582 nid = spec->multiout.dig_out_nid;
583 else
584 nid = codec->slave_dig_outs[smux_idx - 1];
585 if (spec->cur_smux[smux_idx] == smux->num_items - 1)
586 val = AMP_OUT_MUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400587 else
Takashi Iwaic1e99bd2008-10-29 08:03:42 +0100588 val = AMP_OUT_UNMUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400589 /* un/mute SPDIF out */
590 snd_hda_codec_write_cache(codec, nid, 0,
591 AC_VERB_SET_AMP_GAIN_MUTE, val);
592 }
593 return 0;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200594}
595
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100596static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200597{
598 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
599 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200600 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200601}
602
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100603static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200604{
605 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
606 struct sigmatel_spec *spec = codec->spec;
607 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
608
609 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
610 return 0;
611}
612
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100613static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200614{
615 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
616 struct sigmatel_spec *spec = codec->spec;
617 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
618
Mattc7d4b2f2005-06-27 14:59:41 +0200619 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200620 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
621}
622
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100623static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
624 struct snd_ctl_elem_info *uinfo)
625{
626 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
627 struct sigmatel_spec *spec = codec->spec;
628 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
629}
630
631static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
632 struct snd_ctl_elem_value *ucontrol)
633{
634 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
635 struct sigmatel_spec *spec = codec->spec;
636
637 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
638 return 0;
639}
640
641static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
642 struct snd_ctl_elem_value *ucontrol)
643{
644 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
645 struct sigmatel_spec *spec = codec->spec;
646
647 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
648 spec->mono_nid, &spec->cur_mmux);
649}
650
Matthew Ranostay89385032008-09-11 09:49:39 -0400651static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
652 struct snd_ctl_elem_info *uinfo)
653{
654 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
655 struct sigmatel_spec *spec = codec->spec;
656 return snd_hda_input_mux_info(spec->amp_mux, uinfo);
657}
658
659static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
660 struct snd_ctl_elem_value *ucontrol)
661{
662 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
663 struct sigmatel_spec *spec = codec->spec;
664
665 ucontrol->value.enumerated.item[0] = spec->cur_amux;
666 return 0;
667}
668
669static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
670 struct snd_ctl_elem_value *ucontrol)
671{
672 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
673 struct sigmatel_spec *spec = codec->spec;
674 struct snd_kcontrol *ctl =
675 snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
676 if (!ctl)
677 return -EINVAL;
678
679 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
680 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
681
682 return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
683 0, &spec->cur_amux);
684}
685
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200686#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
687
688static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
689 struct snd_ctl_elem_value *ucontrol)
690{
691 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100692 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200693 struct sigmatel_spec *spec = codec->spec;
694
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100695 ucontrol->value.integer.value[0] = !!(spec->aloopback &
696 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200697 return 0;
698}
699
700static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
701 struct snd_ctl_elem_value *ucontrol)
702{
703 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
704 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100705 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200706 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100707 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200708
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100709 idx_val = spec->aloopback_mask << idx;
710 if (ucontrol->value.integer.value[0])
711 val = spec->aloopback | idx_val;
712 else
713 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100714 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200715 return 0;
716
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100717 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200718
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100719 /* Only return the bits defined by the shift value of the
720 * first two bytes of the mask
721 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200722 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100723 kcontrol->private_value & 0xFFFF, 0x0);
724 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200725
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100726 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200727 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100728 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200729 } else {
730 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100731 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200732 }
733
734 snd_hda_codec_write_cache(codec, codec->afg, 0,
735 kcontrol->private_value >> 16, dac_mode);
736
737 return 1;
738}
739
Mattc7d4b2f2005-06-27 14:59:41 +0200740static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200741 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200742 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200743 {}
744};
745
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200746static struct hda_verb stac9200_eapd_init[] = {
747 /* set dac0mux for dac converter */
748 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
749 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
750 {}
751};
752
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100753static struct hda_verb stac92hd73xx_6ch_core_init[] = {
754 /* set master volume and direct control */
755 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
756 /* setup audio connections */
757 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
758 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
759 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
760 /* setup adcs to point to mixer */
761 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
762 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100763 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
764 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
765 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
766 /* setup import muxs */
767 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
768 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
769 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
770 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
771 {}
772};
773
Matthew Ranostayd654a662008-03-14 08:46:51 +0100774static struct hda_verb dell_eq_core_init[] = {
775 /* set master volume to max value without distortion
776 * and direct control */
777 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
778 /* setup audio connections */
779 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
Matthew Ranostayf7cf0a72008-09-13 10:36:58 -0400780 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
781 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayd654a662008-03-14 08:46:51 +0100782 /* setup adcs to point to mixer */
783 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
784 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
785 /* setup import muxs */
786 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
787 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
788 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
789 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
790 {}
791};
792
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100793static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -0500794 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100795 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100796 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
797 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100798 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
799 /* setup adcs to point to mixer */
800 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
801 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
802 /* setup import muxs */
803 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
804 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
805 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
806 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
807 {}
808};
809
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100810static struct hda_verb stac92hd73xx_8ch_core_init[] = {
811 /* set master volume and direct control */
812 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
813 /* setup audio connections */
814 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
815 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
816 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
817 /* connect hp ports to dac3 */
818 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
819 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
820 /* setup adcs to point to mixer */
821 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
822 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100823 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
824 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
825 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
826 /* setup import muxs */
827 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
828 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
829 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
830 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
831 {}
832};
833
834static struct hda_verb stac92hd73xx_10ch_core_init[] = {
835 /* set master volume and direct control */
836 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
837 /* setup audio connections */
838 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
839 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
840 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
841 /* dac3 is connected to import3 mux */
842 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
843 /* connect hp ports to dac4 */
844 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
845 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
846 /* setup adcs to point to mixer */
847 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
848 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100849 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
850 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
851 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
852 /* setup import muxs */
853 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
854 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
855 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
856 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
857 {}
858};
859
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200860static struct hda_verb stac92hd83xxx_core_init[] = {
861 /* start of config #1 */
862 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
863
864 /* start of config #2 */
865 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
866 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
867 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
868
869 /* power state controls amps */
870 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
871};
872
Matthew Ranostaye035b842007-11-06 11:53:55 +0100873static struct hda_verb stac92hd71bxx_core_init[] = {
874 /* set master volume and direct control */
875 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
876 /* connect headphone jack to dac1 */
877 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100878 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
879 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
880 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
881 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100882};
883
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400884#define HD_DISABLE_PORTF 2
Matthew Ranostay541eee82007-12-14 12:08:04 +0100885static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200886 /* start of config #1 */
887
888 /* connect port 0f to audio mixer */
889 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200890 /* unmute right and left channels for node 0x0f */
891 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
892 /* start of config #2 */
893
Matthew Ranostay541eee82007-12-14 12:08:04 +0100894 /* set master volume and direct control */
895 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
896 /* connect headphone jack to dac1 */
897 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200898 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100899 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
900 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100901 {}
902};
903
Tobin Davis8e21c342007-01-08 11:04:17 +0100904static struct hda_verb stac925x_core_init[] = {
905 /* set dac0mux for dac converter */
906 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
907 {}
908};
909
Mattc7d4b2f2005-06-27 14:59:41 +0200910static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200911 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200912 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200913 {}
914};
915
Tobin Davis93ed1502006-09-01 21:03:12 +0200916static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200917 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200918 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200919 /* unmute node 0x1b */
920 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
921 /* select node 0x03 as DAC */
922 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
923 {}
924};
925
Matt Porter3cc08dc2006-01-23 15:27:49 +0100926static struct hda_verb stac927x_core_init[] = {
927 /* set master volume and direct control */
928 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200929 /* enable analog pc beep path */
930 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100931 {}
932};
933
Matt Porterf3302a52006-07-31 12:49:34 +0200934static struct hda_verb stac9205_core_init[] = {
935 /* set master volume and direct control */
936 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200937 /* enable analog pc beep path */
938 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200939 {}
940};
941
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100942#define STAC_MONO_MUX \
943 { \
944 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
945 .name = "Mono Mux", \
946 .count = 1, \
947 .info = stac92xx_mono_mux_enum_info, \
948 .get = stac92xx_mono_mux_enum_get, \
949 .put = stac92xx_mono_mux_enum_put, \
950 }
951
Matthew Ranostay89385032008-09-11 09:49:39 -0400952#define STAC_AMP_MUX \
953 { \
954 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
955 .name = "Amp Selector Capture Switch", \
956 .count = 1, \
957 .info = stac92xx_amp_mux_enum_info, \
958 .get = stac92xx_amp_mux_enum_get, \
959 .put = stac92xx_amp_mux_enum_put, \
960 }
961
962#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
963 { \
964 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
965 .name = xname, \
966 .index = 0, \
967 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
968 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
969 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
970 .info = stac92xx_amp_volume_info, \
971 .get = stac92xx_amp_volume_get, \
972 .put = stac92xx_amp_volume_put, \
973 .tlv = { .c = snd_hda_mixer_amp_tlv }, \
974 .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
975 }
976
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200977#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200978 { \
979 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
980 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200981 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200982 .info = stac92xx_mux_enum_info, \
983 .get = stac92xx_mux_enum_get, \
984 .put = stac92xx_mux_enum_put, \
985 }
986
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100987#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200988 { \
989 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
990 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100991 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200992 .info = stac92xx_aloopback_info, \
993 .get = stac92xx_aloopback_get, \
994 .put = stac92xx_aloopback_put, \
995 .private_value = verb_read | (verb_write << 16), \
996 }
997
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100998static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200999 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
1000 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001001 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +02001002 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
1003 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +02001004 { } /* end */
1005};
1006
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001007#define DELL_M6_MIXER 6
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001008static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001009 /* start of config #1 */
1010 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1011 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1012
1013 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1014 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1015
1016 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1017 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1018
1019 /* start of config #2 */
1020 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1021 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1022
1023 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1024 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1025
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001026 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
1027
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001028 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1029 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1030
1031 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1032 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1033
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001034 { } /* end */
1035};
1036
1037static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001038 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1039
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001040 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1041 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1042
1043 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1044 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1045
1046 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1047 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1048
1049 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1050 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1051
1052 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1053 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1054
1055 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1056 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1057
1058 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1059 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1060 { } /* end */
1061};
1062
1063static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001064 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1065
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001066 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1067 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1068
1069 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1070 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1071
1072 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1073 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1074
1075 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1076 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1077
1078 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1079 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1080
1081 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1082 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1083
1084 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1085 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1086 { } /* end */
1087};
1088
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001089
1090static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
1091 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
1092 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
1093
1094 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
1095 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
1096
1097 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
1098 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
1099
1100 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
1101 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
1102
1103 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
1104 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
1105
1106 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
1107 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
1108
1109 /*
1110 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
1111 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
1112 */
1113 { } /* end */
1114};
1115
Matthew Ranostay541eee82007-12-14 12:08:04 +01001116static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001117 STAC_INPUT_SOURCE(2),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001118 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001119
Matthew Ranostay9b359472007-11-07 13:03:12 +01001120 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1121 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +01001122
1123 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1124 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001125 /* analog pc-beep replaced with digital beep support */
1126 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001127 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
1128 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001129 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001130
Matthew Ranostay687cb982008-10-11 13:52:43 -04001131 HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
1132 HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001133
Matthew Ranostay687cb982008-10-11 13:52:43 -04001134 HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
1135 HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001136
1137 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
1138 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
1139
1140 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
1141 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001142 { } /* end */
1143};
1144
Matthew Ranostay541eee82007-12-14 12:08:04 +01001145static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +01001146 STAC_INPUT_SOURCE(2),
1147 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
1148
Matthew Ranostay541eee82007-12-14 12:08:04 +01001149 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1150 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001151
1152 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1153 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001154 { } /* end */
1155};
1156
Tobin Davis8e21c342007-01-08 11:04:17 +01001157static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001158 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001159 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001160 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001161 { } /* end */
1162};
1163
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001164static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001165 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001166 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001167
1168 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1169 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001170
1171 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1172 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001173 { } /* end */
1174};
1175
1176/* This needs to be generated dynamically based on sequence */
1177static struct snd_kcontrol_new stac922x_mixer[] = {
1178 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001179 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1180 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001181
1182 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1183 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001184 { } /* end */
1185};
1186
1187
1188static struct snd_kcontrol_new stac927x_mixer[] = {
1189 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001190 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001191
1192 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1193 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001194
1195 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1196 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001197
1198 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1199 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001200 { } /* end */
1201};
1202
Takashi Iwai1697055e2007-12-18 18:05:52 +01001203static struct snd_kcontrol_new stac_dmux_mixer = {
1204 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1205 .name = "Digital Input Source",
1206 /* count set later */
1207 .info = stac92xx_dmux_enum_info,
1208 .get = stac92xx_dmux_enum_get,
1209 .put = stac92xx_dmux_enum_put,
1210};
1211
Matthew Ranostayd9737752008-09-07 12:03:41 +02001212static struct snd_kcontrol_new stac_smux_mixer = {
1213 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001214 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001215 /* count set later */
1216 .info = stac92xx_smux_enum_info,
1217 .get = stac92xx_smux_enum_get,
1218 .put = stac92xx_smux_enum_put,
1219};
1220
Takashi Iwai2134ea42008-01-10 16:53:55 +01001221static const char *slave_vols[] = {
1222 "Front Playback Volume",
1223 "Surround Playback Volume",
1224 "Center Playback Volume",
1225 "LFE Playback Volume",
1226 "Side Playback Volume",
1227 "Headphone Playback Volume",
1228 "Headphone Playback Volume",
1229 "Speaker Playback Volume",
1230 "External Speaker Playback Volume",
1231 "Speaker2 Playback Volume",
1232 NULL
1233};
1234
1235static const char *slave_sws[] = {
1236 "Front Playback Switch",
1237 "Surround Playback Switch",
1238 "Center Playback Switch",
1239 "LFE Playback Switch",
1240 "Side Playback Switch",
1241 "Headphone Playback Switch",
1242 "Headphone Playback Switch",
1243 "Speaker Playback Switch",
1244 "External Speaker Playback Switch",
1245 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001246 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001247 NULL
1248};
1249
Takashi Iwai603c4012008-07-30 15:01:44 +02001250static void stac92xx_free_kctls(struct hda_codec *codec);
1251
Matt2f2f4252005-04-13 14:45:30 +02001252static int stac92xx_build_controls(struct hda_codec *codec)
1253{
1254 struct sigmatel_spec *spec = codec->spec;
1255 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001256 int i;
Matt2f2f4252005-04-13 14:45:30 +02001257
1258 err = snd_hda_add_new_ctls(codec, spec->mixer);
1259 if (err < 0)
1260 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001261
1262 for (i = 0; i < spec->num_mixers; i++) {
1263 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1264 if (err < 0)
1265 return err;
1266 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001267 if (spec->num_dmuxes > 0) {
1268 stac_dmux_mixer.count = spec->num_dmuxes;
Takashi Iwaid13bd412008-07-30 15:01:45 +02001269 err = snd_hda_ctl_add(codec,
Takashi Iwai1697055e2007-12-18 18:05:52 +01001270 snd_ctl_new1(&stac_dmux_mixer, codec));
1271 if (err < 0)
1272 return err;
1273 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001274 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001275 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1276 struct hda_input_mux *smux = &spec->private_smux;
1277 /* check for mute support on SPDIF out */
1278 if (wcaps & AC_WCAP_OUT_AMP) {
1279 smux->items[smux->num_items].label = "Off";
1280 smux->items[smux->num_items].index = 0;
1281 smux->num_items++;
1282 spec->spdif_mute = 1;
1283 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001284 stac_smux_mixer.count = spec->num_smuxes;
1285 err = snd_ctl_add(codec->bus->card,
1286 snd_ctl_new1(&stac_smux_mixer, codec));
1287 if (err < 0)
1288 return err;
1289 }
Mattc7d4b2f2005-06-27 14:59:41 +02001290
Mattdabbed62005-06-14 10:19:34 +02001291 if (spec->multiout.dig_out_nid) {
1292 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1293 if (err < 0)
1294 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001295 err = snd_hda_create_spdif_share_sw(codec,
1296 &spec->multiout);
1297 if (err < 0)
1298 return err;
1299 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001300 }
Harvey Harrisonda74ae32008-10-21 20:28:04 -07001301 if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001302 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1303 if (err < 0)
1304 return err;
1305 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001306
1307 /* if we have no master control, let's create it */
1308 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001309 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001310 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001311 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001312 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001313 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001314 if (err < 0)
1315 return err;
1316 }
1317 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1318 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1319 NULL, slave_sws);
1320 if (err < 0)
1321 return err;
1322 }
1323
Takashi Iwai603c4012008-07-30 15:01:44 +02001324 stac92xx_free_kctls(codec); /* no longer needed */
Mattdabbed62005-06-14 10:19:34 +02001325 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001326}
1327
Matt Porter403d1942005-11-29 15:00:51 +01001328static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001329 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001330 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1331};
1332
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001333/*
1334 STAC 9200 pin configs for
1335 102801A8
1336 102801DE
1337 102801E8
1338*/
1339static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001340 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1341 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001342};
1343
1344/*
1345 STAC 9200 pin configs for
1346 102801C0
1347 102801C1
1348*/
1349static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001350 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1351 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001352};
1353
1354/*
1355 STAC 9200 pin configs for
1356 102801C4 (Dell Dimension E310)
1357 102801C5
1358 102801C7
1359 102801D9
1360 102801DA
1361 102801E3
1362*/
1363static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001364 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1365 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001366};
1367
1368
1369/*
1370 STAC 9200-32 pin configs for
1371 102801B5 (Dell Inspiron 630m)
1372 102801D8 (Dell Inspiron 640m)
1373*/
1374static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001375 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1376 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001377};
1378
1379/*
1380 STAC 9200-32 pin configs for
1381 102801C2 (Dell Latitude D620)
1382 102801C8
1383 102801CC (Dell Latitude D820)
1384 102801D4
1385 102801D6
1386*/
1387static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001388 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1389 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001390};
1391
1392/*
1393 STAC 9200-32 pin configs for
1394 102801CE (Dell XPS M1710)
1395 102801CF (Dell Precision M90)
1396*/
1397static unsigned int dell9200_m23_pin_configs[8] = {
1398 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1399 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1400};
1401
1402/*
1403 STAC 9200-32 pin configs for
1404 102801C9
1405 102801CA
1406 102801CB (Dell Latitude 120L)
1407 102801D3
1408*/
1409static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001410 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1411 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001412};
1413
1414/*
1415 STAC 9200-32 pin configs for
1416 102801BD (Dell Inspiron E1505n)
1417 102801EE
1418 102801EF
1419*/
1420static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001421 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1422 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001423};
1424
1425/*
1426 STAC 9200-32 pin configs for
1427 102801F5 (Dell Inspiron 1501)
1428 102801F6
1429*/
1430static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001431 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1432 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001433};
1434
1435/*
1436 STAC 9200-32
1437 102801CD (Dell Inspiron E1705/9400)
1438*/
1439static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001440 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1441 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001442};
1443
Tobin Davisbf277782008-02-03 20:31:47 +01001444static unsigned int oqo9200_pin_configs[8] = {
1445 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1446 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1447};
1448
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001449
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001450static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1451 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001452 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001453 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1454 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1455 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1456 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1457 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1458 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1459 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1460 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1461 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1462 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001463 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001464};
1465
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001466static const char *stac9200_models[STAC_9200_MODELS] = {
1467 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001468 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001469 [STAC_9200_DELL_D21] = "dell-d21",
1470 [STAC_9200_DELL_D22] = "dell-d22",
1471 [STAC_9200_DELL_D23] = "dell-d23",
1472 [STAC_9200_DELL_M21] = "dell-m21",
1473 [STAC_9200_DELL_M22] = "dell-m22",
1474 [STAC_9200_DELL_M23] = "dell-m23",
1475 [STAC_9200_DELL_M24] = "dell-m24",
1476 [STAC_9200_DELL_M25] = "dell-m25",
1477 [STAC_9200_DELL_M26] = "dell-m26",
1478 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001479 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001480 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001481};
1482
1483static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1484 /* SigmaTel reference board */
1485 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1486 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001487 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001488 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1489 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001490 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001491 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1492 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1493 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1494 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1495 "unknown Dell", STAC_9200_DELL_D22),
1496 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1497 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001498 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001499 "Dell Latitude D620", STAC_9200_DELL_M22),
1500 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1501 "unknown Dell", STAC_9200_DELL_D23),
1502 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1503 "unknown Dell", STAC_9200_DELL_D23),
1504 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1505 "unknown Dell", STAC_9200_DELL_M22),
1506 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1507 "unknown Dell", STAC_9200_DELL_M24),
1508 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1509 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001510 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001511 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001512 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001513 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001514 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001515 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001516 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001517 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001518 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001519 "Dell Precision M90", STAC_9200_DELL_M23),
1520 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1521 "unknown Dell", STAC_9200_DELL_M22),
1522 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1523 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001524 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001525 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001526 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001527 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1528 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1529 "unknown Dell", STAC_9200_DELL_D23),
1530 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1531 "unknown Dell", STAC_9200_DELL_D23),
1532 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1533 "unknown Dell", STAC_9200_DELL_D21),
1534 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1535 "unknown Dell", STAC_9200_DELL_D23),
1536 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1537 "unknown Dell", STAC_9200_DELL_D21),
1538 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1539 "unknown Dell", STAC_9200_DELL_M25),
1540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1541 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001543 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1545 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001546 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001547 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001548 /* Gateway machines needs EAPD to be set on resume */
1549 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1550 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1551 STAC_9200_GATEWAY),
1552 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1553 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001554 /* OQO Mobile */
1555 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001556 {} /* terminator */
1557};
1558
Tobin Davis8e21c342007-01-08 11:04:17 +01001559static unsigned int ref925x_pin_configs[8] = {
1560 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001561 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001562};
1563
1564static unsigned int stac925x_MA6_pin_configs[8] = {
1565 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1566 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1567};
1568
Tobin Davis2c11f952007-05-17 09:36:34 +02001569static unsigned int stac925x_PA6_pin_configs[8] = {
1570 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1571 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1572};
1573
Tobin Davis8e21c342007-01-08 11:04:17 +01001574static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001575 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1576 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001577};
1578
1579static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1580 [STAC_REF] = ref925x_pin_configs,
1581 [STAC_M2_2] = stac925xM2_2_pin_configs,
1582 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001583 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001584};
1585
1586static const char *stac925x_models[STAC_925x_MODELS] = {
1587 [STAC_REF] = "ref",
1588 [STAC_M2_2] = "m2-2",
1589 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001590 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001591};
1592
1593static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1594 /* SigmaTel reference board */
1595 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001596 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001597 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1598 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1599 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001600 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001601 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1602 {} /* terminator */
1603};
1604
Matthew Ranostaya7662642008-02-21 07:51:14 +01001605static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001606 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1607 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1608 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001609 0x01452050,
1610};
1611
1612static unsigned int dell_m6_pin_configs[13] = {
1613 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001614 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001615 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1616 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001617};
1618
1619static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001620 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1621 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001622 [STAC_DELL_EQ] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001623};
1624
1625static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1626 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001627 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001628 [STAC_DELL_EQ] = "dell-eq",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001629};
1630
1631static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1632 /* SigmaTel reference board */
1633 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001634 "DFI LanParty", STAC_92HD73XX_REF),
1635 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1636 "unknown Dell", STAC_DELL_M6),
1637 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1638 "unknown Dell", STAC_DELL_M6),
1639 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1640 "unknown Dell", STAC_DELL_M6),
1641 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1642 "unknown Dell", STAC_DELL_M6),
1643 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1644 "unknown Dell", STAC_DELL_M6),
1645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1646 "unknown Dell", STAC_DELL_M6),
1647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1648 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001649 {} /* terminator */
1650};
1651
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001652static unsigned int ref92hd83xxx_pin_configs[14] = {
1653 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1654 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1655 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1656 0x01451160, 0x98560170,
1657};
1658
1659static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1660 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1661};
1662
1663static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1664 [STAC_92HD83XXX_REF] = "ref",
1665};
1666
1667static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1668 /* SigmaTel reference board */
1669 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1670 "DFI LanParty", STAC_92HD71BXX_REF),
1671};
1672
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001673static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001674 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostay4b33c762008-10-10 09:07:23 -04001675 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001676 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001677};
1678
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001679static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001680 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001681 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001682 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001683};
1684
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001685static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001686 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1687 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001688 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001689};
1690
Matthew Ranostaye035b842007-11-06 11:53:55 +01001691static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1692 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001693 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1694 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001695 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001696};
1697
1698static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1699 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001700 [STAC_DELL_M4_1] = "dell-m4-1",
1701 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001702 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001703};
1704
1705static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1706 /* SigmaTel reference board */
1707 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1708 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04001709 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
1710 "unknown HP", STAC_HP_M4),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001711 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1712 "unknown Dell", STAC_DELL_M4_1),
1713 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1714 "unknown Dell", STAC_DELL_M4_1),
1715 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1716 "unknown Dell", STAC_DELL_M4_1),
1717 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1718 "unknown Dell", STAC_DELL_M4_1),
1719 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1720 "unknown Dell", STAC_DELL_M4_1),
1721 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1722 "unknown Dell", STAC_DELL_M4_1),
1723 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1724 "unknown Dell", STAC_DELL_M4_1),
1725 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1726 "unknown Dell", STAC_DELL_M4_2),
1727 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1728 "unknown Dell", STAC_DELL_M4_2),
1729 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1730 "unknown Dell", STAC_DELL_M4_2),
1731 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1732 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001733 {} /* terminator */
1734};
1735
Matt Porter403d1942005-11-29 15:00:51 +01001736static unsigned int ref922x_pin_configs[10] = {
1737 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1738 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001739 0x40000100, 0x40000100,
1740};
1741
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001742/*
1743 STAC 922X pin configs for
1744 102801A7
1745 102801AB
1746 102801A9
1747 102801D1
1748 102801D2
1749*/
1750static unsigned int dell_922x_d81_pin_configs[10] = {
1751 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1752 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1753 0x01813122, 0x400001f2,
1754};
1755
1756/*
1757 STAC 922X pin configs for
1758 102801AC
1759 102801D0
1760*/
1761static unsigned int dell_922x_d82_pin_configs[10] = {
1762 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1763 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1764 0x01813122, 0x400001f1,
1765};
1766
1767/*
1768 STAC 922X pin configs for
1769 102801BF
1770*/
1771static unsigned int dell_922x_m81_pin_configs[10] = {
1772 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1773 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1774 0x40C003f1, 0x405003f0,
1775};
1776
1777/*
1778 STAC 9221 A1 pin configs for
1779 102801D7 (Dell XPS M1210)
1780*/
1781static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001782 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1783 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001784 0x508003f3, 0x405003f4,
1785};
1786
Matt Porter403d1942005-11-29 15:00:51 +01001787static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001788 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001789 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1790 0x02a19120, 0x40000100,
1791};
1792
1793static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001794 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1795 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001796 0x02a19320, 0x40000100,
1797};
1798
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001799static unsigned int intel_mac_v1_pin_configs[10] = {
1800 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1801 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001802 0x400000fc, 0x400000fb,
1803};
1804
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001805static unsigned int intel_mac_v2_pin_configs[10] = {
1806 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1807 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001808 0x400000fc, 0x400000fb,
1809};
1810
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001811static unsigned int intel_mac_v3_pin_configs[10] = {
1812 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1813 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1814 0x400000fc, 0x400000fb,
1815};
1816
1817static unsigned int intel_mac_v4_pin_configs[10] = {
1818 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1819 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1820 0x400000fc, 0x400000fb,
1821};
1822
1823static unsigned int intel_mac_v5_pin_configs[10] = {
1824 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1825 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1826 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001827};
1828
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001829static unsigned int ecs202_pin_configs[10] = {
1830 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1831 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1832 0x9037012e, 0x40e000f2,
1833};
Takashi Iwai76c08822007-06-19 12:17:42 +02001834
Takashi Iwai19039bd2006-06-28 15:52:16 +02001835static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001836 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001837 [STAC_D945GTP3] = d945gtp3_pin_configs,
1838 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001839 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1840 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1841 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1842 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1843 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001844 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001845 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001846 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1847 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1848 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1849 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1850 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1851 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001852 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001853 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1854 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1855 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1856 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001857};
1858
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001859static const char *stac922x_models[STAC_922X_MODELS] = {
1860 [STAC_D945_REF] = "ref",
1861 [STAC_D945GTP5] = "5stack",
1862 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001863 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1864 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1865 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1866 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1867 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001868 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001869 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001870 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001871 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001872 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1873 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001874 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001875 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001876 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001877 [STAC_922X_DELL_D81] = "dell-d81",
1878 [STAC_922X_DELL_D82] = "dell-d82",
1879 [STAC_922X_DELL_M81] = "dell-m81",
1880 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001881};
1882
1883static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1884 /* SigmaTel reference board */
1885 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1886 "DFI LanParty", STAC_D945_REF),
1887 /* Intel 945G based systems */
1888 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1889 "Intel D945G", STAC_D945GTP3),
1890 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1891 "Intel D945G", STAC_D945GTP3),
1892 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1893 "Intel D945G", STAC_D945GTP3),
1894 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1895 "Intel D945G", STAC_D945GTP3),
1896 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1897 "Intel D945G", STAC_D945GTP3),
1898 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1899 "Intel D945G", STAC_D945GTP3),
1900 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1901 "Intel D945G", STAC_D945GTP3),
1902 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1903 "Intel D945G", STAC_D945GTP3),
1904 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1905 "Intel D945G", STAC_D945GTP3),
1906 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1907 "Intel D945G", STAC_D945GTP3),
1908 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1909 "Intel D945G", STAC_D945GTP3),
1910 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1911 "Intel D945G", STAC_D945GTP3),
1912 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1913 "Intel D945G", STAC_D945GTP3),
1914 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1915 "Intel D945G", STAC_D945GTP3),
1916 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1917 "Intel D945G", STAC_D945GTP3),
1918 /* Intel D945G 5-stack systems */
1919 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1920 "Intel D945G", STAC_D945GTP5),
1921 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1922 "Intel D945G", STAC_D945GTP5),
1923 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1924 "Intel D945G", STAC_D945GTP5),
1925 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1926 "Intel D945G", STAC_D945GTP5),
1927 /* Intel 945P based systems */
1928 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1929 "Intel D945P", STAC_D945GTP3),
1930 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1931 "Intel D945P", STAC_D945GTP3),
1932 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1933 "Intel D945P", STAC_D945GTP3),
1934 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1935 "Intel D945P", STAC_D945GTP3),
1936 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1937 "Intel D945P", STAC_D945GTP3),
1938 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1939 "Intel D945P", STAC_D945GTP5),
1940 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001941 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001942 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001943 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001944 /* Dell systems */
1945 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1946 "unknown Dell", STAC_922X_DELL_D81),
1947 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1948 "unknown Dell", STAC_922X_DELL_D81),
1949 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1950 "unknown Dell", STAC_922X_DELL_D81),
1951 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1952 "unknown Dell", STAC_922X_DELL_D82),
1953 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1954 "unknown Dell", STAC_922X_DELL_M81),
1955 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1956 "unknown Dell", STAC_922X_DELL_D82),
1957 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1958 "unknown Dell", STAC_922X_DELL_D81),
1959 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1960 "unknown Dell", STAC_922X_DELL_D81),
1961 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1962 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001963 /* ECS/PC Chips boards */
1964 SND_PCI_QUIRK(0x1019, 0x2144,
1965 "ECS/PC chips", STAC_ECS_202),
1966 SND_PCI_QUIRK(0x1019, 0x2608,
1967 "ECS/PC chips", STAC_ECS_202),
1968 SND_PCI_QUIRK(0x1019, 0x2633,
1969 "ECS/PC chips P17G/1333", STAC_ECS_202),
1970 SND_PCI_QUIRK(0x1019, 0x2811,
1971 "ECS/PC chips", STAC_ECS_202),
1972 SND_PCI_QUIRK(0x1019, 0x2812,
1973 "ECS/PC chips", STAC_ECS_202),
1974 SND_PCI_QUIRK(0x1019, 0x2813,
1975 "ECS/PC chips", STAC_ECS_202),
1976 SND_PCI_QUIRK(0x1019, 0x2814,
1977 "ECS/PC chips", STAC_ECS_202),
1978 SND_PCI_QUIRK(0x1019, 0x2815,
1979 "ECS/PC chips", STAC_ECS_202),
1980 SND_PCI_QUIRK(0x1019, 0x2816,
1981 "ECS/PC chips", STAC_ECS_202),
1982 SND_PCI_QUIRK(0x1019, 0x2817,
1983 "ECS/PC chips", STAC_ECS_202),
1984 SND_PCI_QUIRK(0x1019, 0x2818,
1985 "ECS/PC chips", STAC_ECS_202),
1986 SND_PCI_QUIRK(0x1019, 0x2819,
1987 "ECS/PC chips", STAC_ECS_202),
1988 SND_PCI_QUIRK(0x1019, 0x2820,
1989 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001990 {} /* terminator */
1991};
1992
Matt Porter3cc08dc2006-01-23 15:27:49 +01001993static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001994 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1995 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1996 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1997 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001998};
1999
Tobin Davis93ed1502006-09-01 21:03:12 +02002000static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002001 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
2002 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
2003 0x40000100, 0x40000100, 0x40000100, 0x40000100,
2004 0x40000100, 0x40000100
2005};
2006
Tobin Davis93ed1502006-09-01 21:03:12 +02002007static unsigned int d965_5st_pin_configs[14] = {
2008 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2009 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
2010 0x40000100, 0x40000100, 0x40000100, 0x01442070,
2011 0x40000100, 0x40000100
2012};
2013
Tobin Davis4ff076e2007-08-07 11:48:12 +02002014static unsigned int dell_3st_pin_configs[14] = {
2015 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
2016 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002017 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02002018 0x40c003fc, 0x40000100
2019};
2020
Tobin Davis93ed1502006-09-01 21:03:12 +02002021static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002022 [STAC_D965_REF] = ref927x_pin_configs,
2023 [STAC_D965_3ST] = d965_3st_pin_configs,
2024 [STAC_D965_5ST] = d965_5st_pin_configs,
2025 [STAC_DELL_3ST] = dell_3st_pin_configs,
2026 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002027};
2028
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002029static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002030 [STAC_D965_REF] = "ref",
2031 [STAC_D965_3ST] = "3stack",
2032 [STAC_D965_5ST] = "5stack",
2033 [STAC_DELL_3ST] = "dell-3stack",
2034 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002035};
2036
2037static struct snd_pci_quirk stac927x_cfg_tbl[] = {
2038 /* SigmaTel reference board */
2039 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2040 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002041 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002042 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2043 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002044 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002045 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
2046 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
2047 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
2048 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
2049 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
2050 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
2051 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
2052 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
2053 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
2054 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
2055 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
2056 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
2057 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
2058 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
2059 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
2060 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002061 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002062 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002063 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002064 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2065 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002066 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002067 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
2068 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002069 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02002070 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002071 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2072 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2073 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2074 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002075 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002076 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
2077 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
2078 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
2079 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
2080 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
2081 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
2082 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
2083 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
2084 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002085 {} /* terminator */
2086};
2087
Matt Porterf3302a52006-07-31 12:49:34 +02002088static unsigned int ref9205_pin_configs[12] = {
2089 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002090 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02002091 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02002092};
2093
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002094/*
2095 STAC 9205 pin configs for
2096 102801F1
2097 102801F2
2098 102801FC
2099 102801FD
2100 10280204
2101 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002102 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002103*/
2104static unsigned int dell_9205_m42_pin_configs[12] = {
2105 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
2106 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
2107 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
2108};
2109
2110/*
2111 STAC 9205 pin configs for
2112 102801F9
2113 102801FA
2114 102801FE
2115 102801FF (Dell Precision M4300)
2116 10280206
2117 10280200
2118 10280201
2119*/
2120static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002121 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
2122 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
2123 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
2124};
2125
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002126static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002127 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
2128 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
2129 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
2130};
2131
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002132static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002133 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002134 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
2135 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
2136 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02002137};
2138
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002139static const char *stac9205_models[STAC_9205_MODELS] = {
2140 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002141 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002142 [STAC_9205_DELL_M43] = "dell-m43",
2143 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002144};
2145
2146static struct snd_pci_quirk stac9205_cfg_tbl[] = {
2147 /* SigmaTel reference board */
2148 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2149 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002150 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2151 "unknown Dell", STAC_9205_DELL_M42),
2152 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2153 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002154 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002155 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002156 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2157 "Dell Precision", STAC_9205_DELL_M43),
2158 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2159 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002160 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2161 "unknown Dell", STAC_9205_DELL_M42),
2162 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2163 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002164 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2165 "Dell Precision", STAC_9205_DELL_M43),
2166 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002167 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002168 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2169 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002170 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2171 "Dell Precision", STAC_9205_DELL_M43),
2172 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2173 "Dell Precision", STAC_9205_DELL_M43),
2174 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2175 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002176 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2177 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002178 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2179 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002180 {} /* terminator */
2181};
2182
Richard Fish11b44bb2006-08-23 18:31:34 +02002183static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2184{
2185 int i;
2186 struct sigmatel_spec *spec = codec->spec;
2187
2188 if (! spec->bios_pin_configs) {
2189 spec->bios_pin_configs = kcalloc(spec->num_pins,
2190 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2191 if (! spec->bios_pin_configs)
2192 return -ENOMEM;
2193 }
2194
2195 for (i = 0; i < spec->num_pins; i++) {
2196 hda_nid_t nid = spec->pin_nids[i];
2197 unsigned int pin_cfg;
2198
2199 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2200 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2201 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2202 nid, pin_cfg);
2203 spec->bios_pin_configs[i] = pin_cfg;
2204 }
2205
2206 return 0;
2207}
2208
Matthew Ranostay87d48362007-07-17 11:52:24 +02002209static void stac92xx_set_config_reg(struct hda_codec *codec,
2210 hda_nid_t pin_nid, unsigned int pin_config)
2211{
2212 int i;
2213 snd_hda_codec_write(codec, pin_nid, 0,
2214 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2215 pin_config & 0x000000ff);
2216 snd_hda_codec_write(codec, pin_nid, 0,
2217 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2218 (pin_config & 0x0000ff00) >> 8);
2219 snd_hda_codec_write(codec, pin_nid, 0,
2220 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2221 (pin_config & 0x00ff0000) >> 16);
2222 snd_hda_codec_write(codec, pin_nid, 0,
2223 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2224 pin_config >> 24);
2225 i = snd_hda_codec_read(codec, pin_nid, 0,
2226 AC_VERB_GET_CONFIG_DEFAULT,
2227 0x00);
2228 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2229 pin_nid, i);
2230}
2231
Matt2f2f4252005-04-13 14:45:30 +02002232static void stac92xx_set_config_regs(struct hda_codec *codec)
2233{
2234 int i;
2235 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002236
Matthew Ranostay87d48362007-07-17 11:52:24 +02002237 if (!spec->pin_configs)
2238 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002239
Matthew Ranostay87d48362007-07-17 11:52:24 +02002240 for (i = 0; i < spec->num_pins; i++)
2241 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2242 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002243}
Matt2f2f4252005-04-13 14:45:30 +02002244
Matt2f2f4252005-04-13 14:45:30 +02002245/*
2246 * Analog playback callbacks
2247 */
2248static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2249 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002250 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002251{
2252 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002253 if (spec->stream_delay)
2254 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002255 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2256 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002257}
2258
2259static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2260 struct hda_codec *codec,
2261 unsigned int stream_tag,
2262 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002263 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002264{
2265 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002266 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002267}
2268
2269static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2270 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002271 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002272{
2273 struct sigmatel_spec *spec = codec->spec;
2274 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2275}
2276
2277/*
Mattdabbed62005-06-14 10:19:34 +02002278 * Digital playback callbacks
2279 */
2280static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2281 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002282 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002283{
2284 struct sigmatel_spec *spec = codec->spec;
2285 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2286}
2287
2288static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2289 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002290 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002291{
2292 struct sigmatel_spec *spec = codec->spec;
2293 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2294}
2295
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002296static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2297 struct hda_codec *codec,
2298 unsigned int stream_tag,
2299 unsigned int format,
2300 struct snd_pcm_substream *substream)
2301{
2302 struct sigmatel_spec *spec = codec->spec;
2303 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2304 stream_tag, format, substream);
2305}
2306
Mattdabbed62005-06-14 10:19:34 +02002307
2308/*
Matt2f2f4252005-04-13 14:45:30 +02002309 * Analog capture callbacks
2310 */
2311static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2312 struct hda_codec *codec,
2313 unsigned int stream_tag,
2314 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002315 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002316{
2317 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002318 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002319
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002320 if (spec->powerdown_adcs) {
2321 msleep(40);
2322 snd_hda_codec_write_cache(codec, nid, 0,
2323 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2324 }
2325 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002326 return 0;
2327}
2328
2329static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2330 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002331 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002332{
2333 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002334 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002335
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002336 snd_hda_codec_cleanup_stream(codec, nid);
2337 if (spec->powerdown_adcs)
2338 snd_hda_codec_write_cache(codec, nid, 0,
2339 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002340 return 0;
2341}
2342
Mattdabbed62005-06-14 10:19:34 +02002343static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2344 .substreams = 1,
2345 .channels_min = 2,
2346 .channels_max = 2,
2347 /* NID is set in stac92xx_build_pcms */
2348 .ops = {
2349 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002350 .close = stac92xx_dig_playback_pcm_close,
2351 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002352 },
2353};
2354
2355static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2356 .substreams = 1,
2357 .channels_min = 2,
2358 .channels_max = 2,
2359 /* NID is set in stac92xx_build_pcms */
2360};
2361
Matt2f2f4252005-04-13 14:45:30 +02002362static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2363 .substreams = 1,
2364 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002365 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002366 .nid = 0x02, /* NID to query formats and rates */
2367 .ops = {
2368 .open = stac92xx_playback_pcm_open,
2369 .prepare = stac92xx_playback_pcm_prepare,
2370 .cleanup = stac92xx_playback_pcm_cleanup
2371 },
2372};
2373
Matt Porter3cc08dc2006-01-23 15:27:49 +01002374static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2375 .substreams = 1,
2376 .channels_min = 2,
2377 .channels_max = 2,
2378 .nid = 0x06, /* NID to query formats and rates */
2379 .ops = {
2380 .open = stac92xx_playback_pcm_open,
2381 .prepare = stac92xx_playback_pcm_prepare,
2382 .cleanup = stac92xx_playback_pcm_cleanup
2383 },
2384};
2385
Matt2f2f4252005-04-13 14:45:30 +02002386static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002387 .channels_min = 2,
2388 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002389 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002390 .ops = {
2391 .prepare = stac92xx_capture_pcm_prepare,
2392 .cleanup = stac92xx_capture_pcm_cleanup
2393 },
2394};
2395
2396static int stac92xx_build_pcms(struct hda_codec *codec)
2397{
2398 struct sigmatel_spec *spec = codec->spec;
2399 struct hda_pcm *info = spec->pcm_rec;
2400
2401 codec->num_pcms = 1;
2402 codec->pcm_info = info;
2403
Mattc7d4b2f2005-06-27 14:59:41 +02002404 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002405 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002406 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002407 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002408 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002409
2410 if (spec->alt_switch) {
2411 codec->num_pcms++;
2412 info++;
2413 info->name = "STAC92xx Analog Alt";
2414 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2415 }
Matt2f2f4252005-04-13 14:45:30 +02002416
Mattdabbed62005-06-14 10:19:34 +02002417 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2418 codec->num_pcms++;
2419 info++;
2420 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002421 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002422 if (spec->multiout.dig_out_nid) {
2423 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2424 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2425 }
2426 if (spec->dig_in_nid) {
2427 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2428 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2429 }
2430 }
2431
Matt2f2f4252005-04-13 14:45:30 +02002432 return 0;
2433}
2434
Takashi Iwaic960a032006-03-23 17:06:28 +01002435static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2436{
2437 unsigned int pincap = snd_hda_param_read(codec, nid,
2438 AC_PAR_PIN_CAP);
2439 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2440 if (pincap & AC_PINCAP_VREF_100)
2441 return AC_PINCTL_VREF_100;
2442 if (pincap & AC_PINCAP_VREF_80)
2443 return AC_PINCTL_VREF_80;
2444 if (pincap & AC_PINCAP_VREF_50)
2445 return AC_PINCTL_VREF_50;
2446 if (pincap & AC_PINCAP_VREF_GRD)
2447 return AC_PINCTL_VREF_GRD;
2448 return 0;
2449}
2450
Matt Porter403d1942005-11-29 15:00:51 +01002451static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2452
2453{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002454 snd_hda_codec_write_cache(codec, nid, 0,
2455 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002456}
2457
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002458#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2459
2460static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2461 struct snd_ctl_elem_value *ucontrol)
2462{
2463 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2464 struct sigmatel_spec *spec = codec->spec;
2465
Takashi Iwaid7a89432008-11-12 09:48:04 +01002466 ucontrol->value.integer.value[0] = !!spec->hp_switch;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002467 return 0;
2468}
2469
2470static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2471 struct snd_ctl_elem_value *ucontrol)
2472{
2473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2474 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaid7a89432008-11-12 09:48:04 +01002475 int nid = kcontrol->private_value;
2476
2477 spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002478
2479 /* check to be sure that the ports are upto date with
2480 * switch changes
2481 */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002482 codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002483
2484 return 1;
2485}
2486
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002487#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002488
2489static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2490{
2491 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2492 struct sigmatel_spec *spec = codec->spec;
2493 int io_idx = kcontrol-> private_value & 0xff;
2494
2495 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2496 return 0;
2497}
2498
2499static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2500{
2501 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2502 struct sigmatel_spec *spec = codec->spec;
2503 hda_nid_t nid = kcontrol->private_value >> 8;
2504 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002505 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002506
2507 spec->io_switch[io_idx] = val;
2508
2509 if (val)
2510 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002511 else {
2512 unsigned int pinctl = AC_PINCTL_IN_EN;
2513 if (io_idx) /* set VREF for mic */
2514 pinctl |= stac92xx_get_vref(codec, nid);
2515 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2516 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002517
2518 /* check the auto-mute again: we need to mute/unmute the speaker
2519 * appropriately according to the pin direction
2520 */
2521 if (spec->hp_detect)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04002522 codec->patch_ops.unsol_event(codec,
2523 (STAC_HP_EVENT | nid) << 26);
Jiang Zhe40c1d302007-11-12 13:05:16 +01002524
Matt Porter403d1942005-11-29 15:00:51 +01002525 return 1;
2526}
2527
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002528#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2529
2530static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2531 struct snd_ctl_elem_value *ucontrol)
2532{
2533 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2534 struct sigmatel_spec *spec = codec->spec;
2535
2536 ucontrol->value.integer.value[0] = spec->clfe_swap;
2537 return 0;
2538}
2539
2540static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2541 struct snd_ctl_elem_value *ucontrol)
2542{
2543 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2544 struct sigmatel_spec *spec = codec->spec;
2545 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002546 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002547
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002548 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002549 return 0;
2550
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002551 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002552
2553 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2554 spec->clfe_swap ? 0x4 : 0x0);
2555
2556 return 1;
2557}
2558
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002559#define STAC_CODEC_HP_SWITCH(xname) \
2560 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2561 .name = xname, \
2562 .index = 0, \
2563 .info = stac92xx_hp_switch_info, \
2564 .get = stac92xx_hp_switch_get, \
2565 .put = stac92xx_hp_switch_put, \
2566 }
2567
Matt Porter403d1942005-11-29 15:00:51 +01002568#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2569 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2570 .name = xname, \
2571 .index = 0, \
2572 .info = stac92xx_io_switch_info, \
2573 .get = stac92xx_io_switch_get, \
2574 .put = stac92xx_io_switch_put, \
2575 .private_value = xpval, \
2576 }
2577
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002578#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2579 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2580 .name = xname, \
2581 .index = 0, \
2582 .info = stac92xx_clfe_switch_info, \
2583 .get = stac92xx_clfe_switch_get, \
2584 .put = stac92xx_clfe_switch_put, \
2585 .private_value = xpval, \
2586 }
Matt Porter403d1942005-11-29 15:00:51 +01002587
Mattc7d4b2f2005-06-27 14:59:41 +02002588enum {
2589 STAC_CTL_WIDGET_VOL,
2590 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002591 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002592 STAC_CTL_WIDGET_AMP_MUX,
2593 STAC_CTL_WIDGET_AMP_VOL,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002594 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002595 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002596 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002597};
2598
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002599static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002600 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2601 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002602 STAC_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002603 STAC_AMP_MUX,
2604 STAC_AMP_VOL(NULL, 0, 0, 0, 0),
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002605 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002606 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002607 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002608};
2609
2610/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002611static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
2612 struct snd_kcontrol_new *ktemp,
2613 int idx, const char *name,
2614 unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002615{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002616 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002617
Takashi Iwai603c4012008-07-30 15:01:44 +02002618 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2619 knew = snd_array_new(&spec->kctls);
2620 if (!knew)
2621 return -ENOMEM;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002622 *knew = *ktemp;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002623 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002624 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002625 if (!knew->name)
Mattc7d4b2f2005-06-27 14:59:41 +02002626 return -ENOMEM;
2627 knew->private_value = val;
Mattc7d4b2f2005-06-27 14:59:41 +02002628 return 0;
2629}
2630
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002631static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
2632 int type, int idx, const char *name,
2633 unsigned long val)
2634{
2635 return stac92xx_add_control_temp(spec,
2636 &stac92xx_control_templates[type],
2637 idx, name, val);
2638}
2639
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002640
2641/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01002642static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2643 const char *name, unsigned long val)
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002644{
2645 return stac92xx_add_control_idx(spec, type, 0, name, val);
2646}
2647
Matt Porter403d1942005-11-29 15:00:51 +01002648/* flag inputs as additional dynamic lineouts */
2649static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2650{
2651 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002652 unsigned int wcaps, wtype;
2653 int i, num_dacs = 0;
2654
2655 /* use the wcaps cache to count all DACs available for line-outs */
2656 for (i = 0; i < codec->num_nodes; i++) {
2657 wcaps = codec->wcaps[i];
2658 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002659
Steve Longerbeam7b043892007-05-03 20:50:03 +02002660 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2661 num_dacs++;
2662 }
Matt Porter403d1942005-11-29 15:00:51 +01002663
Steve Longerbeam7b043892007-05-03 20:50:03 +02002664 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2665
Matt Porter403d1942005-11-29 15:00:51 +01002666 switch (cfg->line_outs) {
2667 case 3:
2668 /* add line-in as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002669 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002670 cfg->line_out_pins[cfg->line_outs] =
2671 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002672 spec->line_switch = 1;
2673 cfg->line_outs++;
2674 }
2675 break;
2676 case 2:
2677 /* add line-in as clfe and mic as side */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002678 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002679 cfg->line_out_pins[cfg->line_outs] =
2680 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002681 spec->line_switch = 1;
2682 cfg->line_outs++;
2683 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002684 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002685 cfg->line_out_pins[cfg->line_outs] =
2686 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002687 spec->mic_switch = 1;
2688 cfg->line_outs++;
2689 }
2690 break;
2691 case 1:
2692 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b043892007-05-03 20:50:03 +02002693 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002694 cfg->line_out_pins[cfg->line_outs] =
2695 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002696 spec->line_switch = 1;
2697 cfg->line_outs++;
2698 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002699 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002700 cfg->line_out_pins[cfg->line_outs] =
2701 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002702 spec->mic_switch = 1;
2703 cfg->line_outs++;
2704 }
2705 break;
2706 }
2707
2708 return 0;
2709}
2710
Steve Longerbeam7b043892007-05-03 20:50:03 +02002711
2712static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2713{
2714 int i;
2715
2716 for (i = 0; i < spec->multiout.num_dacs; i++) {
2717 if (spec->multiout.dac_nids[i] == nid)
2718 return 1;
2719 }
2720
2721 return 0;
2722}
2723
Matt Porter3cc08dc2006-01-23 15:27:49 +01002724/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02002725 * Fill in the dac_nids table from the parsed pin configuration
2726 * This function only works when every pin in line_out_pins[]
2727 * contains atleast one DAC in its connection list. Some 92xx
2728 * codecs are not connected directly to a DAC, such as the 9200
2729 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002730 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002731static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002732 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002733{
2734 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002735 int i, j, conn_len = 0;
2736 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2737 unsigned int wcaps, wtype;
2738
Mattc7d4b2f2005-06-27 14:59:41 +02002739 for (i = 0; i < cfg->line_outs; i++) {
2740 nid = cfg->line_out_pins[i];
Steve Longerbeam7b043892007-05-03 20:50:03 +02002741 conn_len = snd_hda_get_connections(codec, nid, conn,
2742 HDA_MAX_CONNECTIONS);
2743 for (j = 0; j < conn_len; j++) {
2744 wcaps = snd_hda_param_read(codec, conn[j],
2745 AC_PAR_AUDIO_WIDGET_CAP);
2746 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b043892007-05-03 20:50:03 +02002747 if (wtype != AC_WID_AUD_OUT ||
2748 (wcaps & AC_WCAP_DIGITAL))
2749 continue;
2750 /* conn[j] is a DAC routed to this line-out */
2751 if (!is_in_dac_nids(spec, conn[j]))
2752 break;
2753 }
2754
2755 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002756 if (spec->multiout.num_dacs > 0) {
2757 /* we have already working output pins,
2758 * so let's drop the broken ones again
2759 */
2760 cfg->line_outs = spec->multiout.num_dacs;
2761 break;
2762 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02002763 /* error out, no available DAC found */
2764 snd_printk(KERN_ERR
2765 "%s: No available DAC for pin 0x%x\n",
2766 __func__, nid);
2767 return -ENODEV;
2768 }
2769
2770 spec->multiout.dac_nids[i] = conn[j];
2771 spec->multiout.num_dacs++;
2772 if (conn_len > 1) {
2773 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002774 snd_hda_codec_write_cache(codec, nid, 0,
2775 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b043892007-05-03 20:50:03 +02002776
2777 }
Mattc7d4b2f2005-06-27 14:59:41 +02002778 }
2779
Steve Longerbeam7b043892007-05-03 20:50:03 +02002780 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2781 spec->multiout.num_dacs,
2782 spec->multiout.dac_nids[0],
2783 spec->multiout.dac_nids[1],
2784 spec->multiout.dac_nids[2],
2785 spec->multiout.dac_nids[3],
2786 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002787 return 0;
2788}
2789
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002790/* create volume control/switch for the given prefx type */
2791static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2792{
2793 char name[32];
2794 int err;
2795
2796 sprintf(name, "%s Playback Volume", pfx);
2797 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2798 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2799 if (err < 0)
2800 return err;
2801 sprintf(name, "%s Playback Switch", pfx);
2802 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2803 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2804 if (err < 0)
2805 return err;
2806 return 0;
2807}
2808
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002809static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2810{
2811 if (!spec->multiout.hp_nid)
2812 spec->multiout.hp_nid = nid;
2813 else if (spec->multiout.num_dacs > 4) {
2814 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2815 return 1;
2816 } else {
2817 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2818 spec->multiout.num_dacs++;
2819 }
2820 return 0;
2821}
2822
2823static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2824{
2825 if (is_in_dac_nids(spec, nid))
2826 return 1;
2827 if (spec->multiout.hp_nid == nid)
2828 return 1;
2829 return 0;
2830}
2831
Mattc7d4b2f2005-06-27 14:59:41 +02002832/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002833static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002834 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002835{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002836 static const char *chname[4] = {
2837 "Front", "Surround", NULL /*CLFE*/, "Side"
2838 };
Matthew Ranostayd21995e2008-10-13 13:22:45 -04002839 hda_nid_t nid = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02002840 int i, err;
2841
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002842 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002843 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002844
2845
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002846 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002847 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002848 continue;
2849
2850 nid = spec->multiout.dac_nids[i];
2851
2852 if (i == 2) {
2853 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002854 err = create_controls(spec, "Center", nid, 1);
2855 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002856 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002857 err = create_controls(spec, "LFE", nid, 2);
2858 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002859 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002860
2861 wid_caps = get_wcaps(codec, nid);
2862
2863 if (wid_caps & AC_WCAP_LR_SWAP) {
2864 err = stac92xx_add_control(spec,
2865 STAC_CTL_WIDGET_CLFE_SWITCH,
2866 "Swap Center/LFE Playback Switch", nid);
2867
2868 if (err < 0)
2869 return err;
2870 }
2871
Mattc7d4b2f2005-06-27 14:59:41 +02002872 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002873 err = create_controls(spec, chname[i], nid, 3);
2874 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002875 return err;
2876 }
2877 }
2878
Matthew Ranostayfedb7562008-09-23 21:46:30 -04002879 if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
2880 cfg->hp_outs && !spec->multiout.hp_nid)
2881 spec->multiout.hp_nid = nid;
2882
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002883 if (cfg->hp_outs > 1) {
2884 err = stac92xx_add_control(spec,
2885 STAC_CTL_WIDGET_HP_SWITCH,
Takashi Iwaid7a89432008-11-12 09:48:04 +01002886 "Headphone as Line Out Switch",
2887 cfg->hp_pins[cfg->hp_outs - 1]);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002888 if (err < 0)
2889 return err;
2890 }
2891
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002892 if (spec->line_switch) {
2893 nid = cfg->input_pins[AUTO_PIN_LINE];
2894 pincap = snd_hda_param_read(codec, nid,
2895 AC_PAR_PIN_CAP);
2896 if (pincap & AC_PINCAP_OUT) {
2897 err = stac92xx_add_control(spec,
2898 STAC_CTL_WIDGET_IO_SWITCH,
2899 "Line In as Output Switch", nid << 8);
2900 if (err < 0)
2901 return err;
2902 }
2903 }
Matt Porter403d1942005-11-29 15:00:51 +01002904
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002905 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002906 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002907 unsigned int mic_pin = AUTO_PIN_MIC;
2908again:
2909 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002910 def_conf = snd_hda_codec_read(codec, nid, 0,
2911 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002912 /* some laptops have an internal analog microphone
2913 * which can't be used as a output */
2914 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2915 pincap = snd_hda_param_read(codec, nid,
2916 AC_PAR_PIN_CAP);
2917 if (pincap & AC_PINCAP_OUT) {
2918 err = stac92xx_add_control(spec,
2919 STAC_CTL_WIDGET_IO_SWITCH,
2920 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002921 nid = snd_hda_codec_read(codec, nid, 0,
2922 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2923 if (!check_in_dac_nids(spec, nid))
2924 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002925 if (err < 0)
2926 return err;
2927 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002928 } else if (mic_pin == AUTO_PIN_MIC) {
2929 mic_pin = AUTO_PIN_FRONT_MIC;
2930 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002931 }
2932 }
Matt Porter403d1942005-11-29 15:00:51 +01002933
Mattc7d4b2f2005-06-27 14:59:41 +02002934 return 0;
2935}
2936
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002937/* add playback controls for Speaker and HP outputs */
2938static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2939 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002940{
2941 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002942 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002943 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002944
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002945 old_num_dacs = spec->multiout.num_dacs;
2946 for (i = 0; i < cfg->hp_outs; i++) {
2947 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2948 if (wid_caps & AC_WCAP_UNSOL_CAP)
2949 spec->hp_detect = 1;
2950 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2951 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2952 if (check_in_dac_nids(spec, nid))
2953 nid = 0;
2954 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002955 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002956 add_spec_dacs(spec, nid);
2957 }
2958 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b043892007-05-03 20:50:03 +02002959 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002960 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2961 if (check_in_dac_nids(spec, nid))
2962 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002963 if (! nid)
2964 continue;
2965 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002966 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002967 for (i = 0; i < cfg->line_outs; i++) {
2968 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2969 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2970 if (check_in_dac_nids(spec, nid))
2971 nid = 0;
2972 if (! nid)
2973 continue;
2974 add_spec_dacs(spec, nid);
2975 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002976 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2977 static const char *pfxs[] = {
2978 "Speaker", "External Speaker", "Speaker2",
2979 };
2980 err = create_controls(spec, pfxs[i - old_num_dacs],
2981 spec->multiout.dac_nids[i], 3);
2982 if (err < 0)
2983 return err;
2984 }
2985 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002986 err = create_controls(spec, "Headphone",
2987 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002988 if (err < 0)
2989 return err;
2990 }
Mattc7d4b2f2005-06-27 14:59:41 +02002991
2992 return 0;
2993}
2994
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002995/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002996static const char *stac92xx_mono_labels[4] = {
2997 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002998};
2999
3000/* create mono mux for mono out on capable codecs */
3001static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
3002{
3003 struct sigmatel_spec *spec = codec->spec;
3004 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
3005 int i, num_cons;
3006 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
3007
3008 num_cons = snd_hda_get_connections(codec,
3009 spec->mono_nid,
3010 con_lst,
3011 HDA_MAX_NUM_INPUTS);
3012 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
3013 return -EINVAL;
3014
3015 for (i = 0; i < num_cons; i++) {
3016 mono_mux->items[mono_mux->num_items].label =
3017 stac92xx_mono_labels[i];
3018 mono_mux->items[mono_mux->num_items].index = i;
3019 mono_mux->num_items++;
3020 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003021
3022 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
3023 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003024}
3025
Matthew Ranostay89385032008-09-11 09:49:39 -04003026/* labels for amp mux outputs */
3027static const char *stac92xx_amp_labels[3] = {
Matthew Ranostay4b33c762008-10-10 09:07:23 -04003028 "Front Microphone", "Microphone", "Line In",
Matthew Ranostay89385032008-09-11 09:49:39 -04003029};
3030
3031/* create amp out controls mux on capable codecs */
3032static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
3033{
3034 struct sigmatel_spec *spec = codec->spec;
3035 struct hda_input_mux *amp_mux = &spec->private_amp_mux;
3036 int i, err;
3037
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003038 for (i = 0; i < spec->num_amps; i++) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003039 amp_mux->items[amp_mux->num_items].label =
3040 stac92xx_amp_labels[i];
3041 amp_mux->items[amp_mux->num_items].index = i;
3042 amp_mux->num_items++;
3043 }
3044
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003045 if (spec->num_amps > 1) {
3046 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
3047 "Amp Selector Capture Switch", 0);
3048 if (err < 0)
3049 return err;
3050 }
Matthew Ranostay89385032008-09-11 09:49:39 -04003051 return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
3052 "Amp Capture Volume",
3053 HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
3054}
3055
3056
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003057/* create PC beep volume controls */
3058static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3059 hda_nid_t nid)
3060{
3061 struct sigmatel_spec *spec = codec->spec;
3062 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3063 int err;
3064
3065 /* check for mute support for the the amp */
3066 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3067 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3068 "PC Beep Playback Switch",
3069 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3070 if (err < 0)
3071 return err;
3072 }
3073
3074 /* check to see if there is volume support for the amp */
3075 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3076 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
3077 "PC Beep Playback Volume",
3078 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3079 if (err < 0)
3080 return err;
3081 }
3082 return 0;
3083}
3084
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003085#ifdef CONFIG_SND_HDA_INPUT_BEEP
3086#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
3087
3088static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
3089 struct snd_ctl_elem_value *ucontrol)
3090{
3091 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3092 ucontrol->value.integer.value[0] = codec->beep->enabled;
3093 return 0;
3094}
3095
3096static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
3097 struct snd_ctl_elem_value *ucontrol)
3098{
3099 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3100 int enabled = !!ucontrol->value.integer.value[0];
3101 if (codec->beep->enabled != enabled) {
3102 codec->beep->enabled = enabled;
3103 return 1;
3104 }
3105 return 0;
3106}
3107
3108static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
3109 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3110 .info = stac92xx_dig_beep_switch_info,
3111 .get = stac92xx_dig_beep_switch_get,
3112 .put = stac92xx_dig_beep_switch_put,
3113};
3114
3115static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
3116{
3117 return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
3118 0, "PC Beep Playback Switch", 0);
3119}
3120#endif
3121
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003122static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3123{
3124 struct sigmatel_spec *spec = codec->spec;
3125 int wcaps, nid, i, err = 0;
3126
3127 for (i = 0; i < spec->num_muxes; i++) {
3128 nid = spec->mux_nids[i];
3129 wcaps = get_wcaps(codec, nid);
3130
3131 if (wcaps & AC_WCAP_OUT_AMP) {
3132 err = stac92xx_add_control_idx(spec,
3133 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
3134 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3135 if (err < 0)
3136 return err;
3137 }
3138 }
3139 return 0;
3140};
3141
Matthew Ranostayd9737752008-09-07 12:03:41 +02003142static const char *stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04003143 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02003144};
3145
3146static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
3147{
3148 struct sigmatel_spec *spec = codec->spec;
3149 struct hda_input_mux *spdif_mux = &spec->private_smux;
Matthew Ranostay65973632008-09-16 10:39:37 -04003150 const char **labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003151 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04003152 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003153
3154 num_cons = snd_hda_get_connections(codec,
3155 spec->smux_nids[0],
3156 con_lst,
3157 HDA_MAX_NUM_INPUTS);
Matthew Ranostay65973632008-09-16 10:39:37 -04003158 if (!num_cons)
Matthew Ranostayd9737752008-09-07 12:03:41 +02003159 return -EINVAL;
3160
Matthew Ranostay65973632008-09-16 10:39:37 -04003161 if (!labels)
3162 labels = stac92xx_spdif_labels;
3163
Matthew Ranostayd9737752008-09-07 12:03:41 +02003164 for (i = 0; i < num_cons; i++) {
Matthew Ranostay65973632008-09-16 10:39:37 -04003165 spdif_mux->items[spdif_mux->num_items].label = labels[i];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003166 spdif_mux->items[spdif_mux->num_items].index = i;
3167 spdif_mux->num_items++;
3168 }
3169
3170 return 0;
3171}
3172
Matt Porter8b657272006-10-26 17:12:59 +02003173/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01003174static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02003175 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
3176 "Digital Mic 3", "Digital Mic 4"
3177};
3178
3179/* create playback/capture controls for input pins on dmic capable codecs */
3180static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3181 const struct auto_pin_cfg *cfg)
3182{
3183 struct sigmatel_spec *spec = codec->spec;
3184 struct hda_input_mux *dimux = &spec->private_dimux;
3185 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003186 int err, i, j;
3187 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02003188
3189 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
3190 dimux->items[dimux->num_items].index = 0;
3191 dimux->num_items++;
3192
3193 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003194 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02003195 int index;
3196 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003197 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02003198 unsigned int def_conf;
3199
3200 def_conf = snd_hda_codec_read(codec,
3201 spec->dmic_nids[i],
3202 0,
3203 AC_VERB_GET_CONFIG_DEFAULT,
3204 0);
3205 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
3206 continue;
3207
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003208 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02003209 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003210 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02003211 con_lst,
3212 HDA_MAX_NUM_INPUTS);
3213 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003214 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02003215 index = j;
3216 goto found;
3217 }
3218 continue;
3219found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003220 wcaps = get_wcaps(codec, nid) &
3221 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003222
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003223 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003224 sprintf(name, "%s Capture Volume",
3225 stac92xx_dmic_labels[dimux->num_items]);
3226
3227 err = stac92xx_add_control(spec,
3228 STAC_CTL_WIDGET_VOL,
3229 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003230 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3231 (wcaps & AC_WCAP_OUT_AMP) ?
3232 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003233 if (err < 0)
3234 return err;
3235 }
3236
Matt Porter8b657272006-10-26 17:12:59 +02003237 dimux->items[dimux->num_items].label =
3238 stac92xx_dmic_labels[dimux->num_items];
3239 dimux->items[dimux->num_items].index = index;
3240 dimux->num_items++;
3241 }
3242
3243 return 0;
3244}
3245
Mattc7d4b2f2005-06-27 14:59:41 +02003246/* create playback/capture controls for input pins */
3247static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3248{
3249 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003250 struct hda_input_mux *imux = &spec->private_imux;
3251 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3252 int i, j, k;
3253
3254 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003255 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003256
Takashi Iwai314634b2006-09-21 11:56:18 +02003257 if (!cfg->input_pins[i])
3258 continue;
3259 index = -1;
3260 for (j = 0; j < spec->num_muxes; j++) {
3261 int num_cons;
3262 num_cons = snd_hda_get_connections(codec,
3263 spec->mux_nids[j],
3264 con_lst,
3265 HDA_MAX_NUM_INPUTS);
3266 for (k = 0; k < num_cons; k++)
3267 if (con_lst[k] == cfg->input_pins[i]) {
3268 index = k;
3269 goto found;
3270 }
Mattc7d4b2f2005-06-27 14:59:41 +02003271 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003272 continue;
3273 found:
3274 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3275 imux->items[imux->num_items].index = index;
3276 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003277 }
3278
Steve Longerbeam7b043892007-05-03 20:50:03 +02003279 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003280 /*
3281 * Set the current input for the muxes.
3282 * The STAC9221 has two input muxes with identical source
3283 * NID lists. Hopefully this won't get confused.
3284 */
3285 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003286 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3287 AC_VERB_SET_CONNECT_SEL,
3288 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003289 }
3290 }
3291
Mattc7d4b2f2005-06-27 14:59:41 +02003292 return 0;
3293}
3294
Mattc7d4b2f2005-06-27 14:59:41 +02003295static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3296{
3297 struct sigmatel_spec *spec = codec->spec;
3298 int i;
3299
3300 for (i = 0; i < spec->autocfg.line_outs; i++) {
3301 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3302 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3303 }
3304}
3305
3306static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3307{
3308 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003309 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003310
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003311 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3312 hda_nid_t pin;
3313 pin = spec->autocfg.hp_pins[i];
3314 if (pin) /* connect to front */
3315 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3316 }
3317 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3318 hda_nid_t pin;
3319 pin = spec->autocfg.speaker_pins[i];
3320 if (pin) /* connect to front */
3321 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3322 }
Mattc7d4b2f2005-06-27 14:59:41 +02003323}
3324
Matt Porter3cc08dc2006-01-23 15:27:49 +01003325static 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 +02003326{
3327 struct sigmatel_spec *spec = codec->spec;
3328 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003329 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003330
Matt Porter8b657272006-10-26 17:12:59 +02003331 if ((err = snd_hda_parse_pin_def_config(codec,
3332 &spec->autocfg,
3333 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003334 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003335 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003336 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003337
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003338 /* If we have no real line-out pin and multiple hp-outs, HPs should
3339 * be set up as multi-channel outputs.
3340 */
3341 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3342 spec->autocfg.hp_outs > 1) {
3343 /* Copy hp_outs to line_outs, backup line_outs in
3344 * speaker_outs so that the following routines can handle
3345 * HP pins as primary outputs.
3346 */
3347 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3348 sizeof(spec->autocfg.line_out_pins));
3349 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3350 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3351 sizeof(spec->autocfg.hp_pins));
3352 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3353 hp_speaker_swap = 1;
3354 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003355 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003356 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3357 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003358 u32 caps = query_amp_caps(codec,
3359 spec->autocfg.mono_out_pin, dir);
3360 hda_nid_t conn_list[1];
3361
3362 /* get the mixer node and then the mono mux if it exists */
3363 if (snd_hda_get_connections(codec,
3364 spec->autocfg.mono_out_pin, conn_list, 1) &&
3365 snd_hda_get_connections(codec, conn_list[0],
3366 conn_list, 1)) {
3367
3368 int wcaps = get_wcaps(codec, conn_list[0]);
3369 int wid_type = (wcaps & AC_WCAP_TYPE)
3370 >> AC_WCAP_TYPE_SHIFT;
3371 /* LR swap check, some stac925x have a mux that
3372 * changes the DACs output path instead of the
3373 * mono-mux path.
3374 */
3375 if (wid_type == AC_WID_AUD_SEL &&
3376 !(wcaps & AC_WCAP_LR_SWAP))
3377 spec->mono_nid = conn_list[0];
3378 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003379 if (dir) {
3380 hda_nid_t nid = spec->autocfg.mono_out_pin;
3381
3382 /* most mono outs have a least a mute/unmute switch */
3383 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3384 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3385 "Mono Playback Switch",
3386 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003387 if (err < 0)
3388 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003389 /* check for volume support for the amp */
3390 if ((caps & AC_AMPCAP_NUM_STEPS)
3391 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3392 err = stac92xx_add_control(spec,
3393 STAC_CTL_WIDGET_VOL,
3394 "Mono Playback Volume",
3395 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3396 if (err < 0)
3397 return err;
3398 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003399 }
3400
3401 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3402 AC_PINCTL_OUT_EN);
3403 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003404
Matt Porter403d1942005-11-29 15:00:51 +01003405 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3406 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003407 if (spec->multiout.num_dacs == 0)
3408 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3409 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003410
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003411 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3412
3413 if (err < 0)
3414 return err;
3415
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003416 /* setup analog beep controls */
3417 if (spec->anabeep_nid > 0) {
3418 err = stac92xx_auto_create_beep_ctls(codec,
3419 spec->anabeep_nid);
3420 if (err < 0)
3421 return err;
3422 }
3423
3424 /* setup digital beep controls and input device */
3425#ifdef CONFIG_SND_HDA_INPUT_BEEP
3426 if (spec->digbeep_nid > 0) {
3427 hda_nid_t nid = spec->digbeep_nid;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003428 unsigned int caps;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003429
3430 err = stac92xx_auto_create_beep_ctls(codec, nid);
3431 if (err < 0)
3432 return err;
3433 err = snd_hda_attach_beep_device(codec, nid);
3434 if (err < 0)
3435 return err;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003436 /* if no beep switch is available, make its own one */
3437 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3438 if (codec->beep &&
3439 !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) {
3440 err = stac92xx_beep_switch_ctl(codec);
3441 if (err < 0)
3442 return err;
3443 }
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003444 }
3445#endif
3446
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003447 if (hp_speaker_swap == 1) {
3448 /* Restore the hp_outs and line_outs */
3449 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3450 sizeof(spec->autocfg.line_out_pins));
3451 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3452 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3453 sizeof(spec->autocfg.speaker_pins));
3454 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3455 memset(spec->autocfg.speaker_pins, 0,
3456 sizeof(spec->autocfg.speaker_pins));
3457 spec->autocfg.speaker_outs = 0;
3458 }
3459
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003460 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3461
3462 if (err < 0)
3463 return err;
3464
3465 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3466
3467 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003468 return err;
3469
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003470 if (spec->mono_nid > 0) {
3471 err = stac92xx_auto_create_mono_output_ctls(codec);
3472 if (err < 0)
3473 return err;
3474 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003475 if (spec->num_amps > 0) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003476 err = stac92xx_auto_create_amp_output_ctls(codec);
3477 if (err < 0)
3478 return err;
3479 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003480 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02003481 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3482 &spec->autocfg)) < 0)
3483 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003484 if (spec->num_muxes > 0) {
3485 err = stac92xx_auto_create_mux_input_ctls(codec);
3486 if (err < 0)
3487 return err;
3488 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003489 if (spec->num_smuxes > 0) {
3490 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3491 if (err < 0)
3492 return err;
3493 }
Matt Porter8b657272006-10-26 17:12:59 +02003494
Mattc7d4b2f2005-06-27 14:59:41 +02003495 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003496 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003497 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003498
Takashi Iwai82bc9552006-03-21 11:24:42 +01003499 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003500 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003501 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003502 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003503
Takashi Iwai603c4012008-07-30 15:01:44 +02003504 if (spec->kctls.list)
3505 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003506
3507 spec->input_mux = &spec->private_imux;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003508 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003509 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003510 spec->mono_mux = &spec->private_mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -04003511 spec->amp_mux = &spec->private_amp_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003512 return 1;
3513}
3514
Takashi Iwai82bc9552006-03-21 11:24:42 +01003515/* add playback controls for HP output */
3516static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3517 struct auto_pin_cfg *cfg)
3518{
3519 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003520 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003521 unsigned int wid_caps;
3522
3523 if (! pin)
3524 return 0;
3525
3526 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003527 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003528 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003529
3530 return 0;
3531}
3532
Richard Fish160ea0d2006-09-06 13:58:25 +02003533/* add playback controls for LFE output */
3534static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3535 struct auto_pin_cfg *cfg)
3536{
3537 struct sigmatel_spec *spec = codec->spec;
3538 int err;
3539 hda_nid_t lfe_pin = 0x0;
3540 int i;
3541
3542 /*
3543 * search speaker outs and line outs for a mono speaker pin
3544 * with an amp. If one is found, add LFE controls
3545 * for it.
3546 */
3547 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3548 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003549 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003550 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3551 if (wcaps == AC_WCAP_OUT_AMP)
3552 /* found a mono speaker with an amp, must be lfe */
3553 lfe_pin = pin;
3554 }
3555
3556 /* if speaker_outs is 0, then speakers may be in line_outs */
3557 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3558 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3559 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003560 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003561 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003562 AC_VERB_GET_CONFIG_DEFAULT,
3563 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003564 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003565 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003566 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3567 if (wcaps == AC_WCAP_OUT_AMP)
3568 /* found a mono speaker with an amp,
3569 must be lfe */
3570 lfe_pin = pin;
3571 }
3572 }
3573 }
3574
3575 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003576 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003577 if (err < 0)
3578 return err;
3579 }
3580
3581 return 0;
3582}
3583
Mattc7d4b2f2005-06-27 14:59:41 +02003584static int stac9200_parse_auto_config(struct hda_codec *codec)
3585{
3586 struct sigmatel_spec *spec = codec->spec;
3587 int err;
3588
Kailang Yangdf694da2005-12-05 19:42:22 +01003589 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003590 return err;
3591
3592 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3593 return err;
3594
Takashi Iwai82bc9552006-03-21 11:24:42 +01003595 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3596 return err;
3597
Richard Fish160ea0d2006-09-06 13:58:25 +02003598 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3599 return err;
3600
Takashi Iwai355a0ec2008-11-11 16:46:19 +01003601 if (spec->num_muxes > 0) {
3602 err = stac92xx_auto_create_mux_input_ctls(codec);
3603 if (err < 0)
3604 return err;
3605 }
3606
Takashi Iwai82bc9552006-03-21 11:24:42 +01003607 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003608 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003609 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003610 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003611
Takashi Iwai603c4012008-07-30 15:01:44 +02003612 if (spec->kctls.list)
3613 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02003614
3615 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003616 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003617
3618 return 1;
3619}
3620
Sam Revitch62fe78e2006-05-10 15:09:17 +02003621/*
3622 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3623 * funky external mute control using GPIO pins.
3624 */
3625
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003626static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003627 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003628{
3629 unsigned int gpiostate, gpiomask, gpiodir;
3630
3631 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3632 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003633 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003634
3635 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3636 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003637 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003638
3639 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3640 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003641 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003642
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003643 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003644 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3645
3646 snd_hda_codec_write(codec, codec->afg, 0,
3647 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003648 snd_hda_codec_read(codec, codec->afg, 0,
3649 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003650
3651 msleep(1);
3652
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003653 snd_hda_codec_read(codec, codec->afg, 0,
3654 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003655}
3656
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003657static int stac92xx_add_jack(struct hda_codec *codec,
3658 hda_nid_t nid, int type)
3659{
3660 struct sigmatel_spec *spec = codec->spec;
3661 struct sigmatel_jack *jack;
3662 int def_conf = snd_hda_codec_read(codec, nid,
3663 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
3664 int connectivity = get_defcfg_connect(def_conf);
3665 char name[32];
3666
3667 if (connectivity && connectivity != AC_JACK_PORT_FIXED)
3668 return 0;
3669
3670 snd_array_init(&spec->jacks, sizeof(*jack), 32);
3671 jack = snd_array_new(&spec->jacks);
3672 if (!jack)
3673 return -ENOMEM;
3674 jack->nid = nid;
3675 jack->type = type;
3676
3677 sprintf(name, "%s at %s %s Jack",
3678 snd_hda_get_jack_type(def_conf),
3679 snd_hda_get_jack_connectivity(def_conf),
3680 snd_hda_get_jack_location(def_conf));
3681
3682 return snd_jack_new(codec->bus->card, name, type, &jack->jack);
3683}
3684
3685static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
3686 int data)
3687{
3688 struct sigmatel_event *event;
3689
3690 snd_array_init(&spec->events, sizeof(*event), 32);
3691 event = snd_array_new(&spec->events);
3692 if (!event)
3693 return -ENOMEM;
3694 event->nid = nid;
3695 event->data = data;
3696
3697 return 0;
3698}
3699
3700static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid)
3701{
3702 struct sigmatel_spec *spec = codec->spec;
3703 struct sigmatel_event *events = spec->events.list;
3704 if (events) {
3705 int i;
3706 for (i = 0; i < spec->events.used; i++)
3707 if (events[i].nid == nid)
3708 return events[i].data;
3709 }
3710 return 0;
3711}
3712
Takashi Iwai314634b2006-09-21 11:56:18 +02003713static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3714 unsigned int event)
3715{
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003716 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003717 snd_hda_codec_write_cache(codec, nid, 0,
3718 AC_VERB_SET_UNSOLICITED_ENABLE,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003719 (AC_USRSP_EN | event | nid));
3720 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003721}
3722
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003723static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3724{
3725 int i;
3726 for (i = 0; i < cfg->hp_outs; i++)
3727 if (cfg->hp_pins[i] == nid)
3728 return 1; /* nid is a HP-Out */
3729
3730 return 0; /* nid is not a HP-Out */
3731};
3732
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003733static void stac92xx_power_down(struct hda_codec *codec)
3734{
3735 struct sigmatel_spec *spec = codec->spec;
3736
3737 /* power down inactive DACs */
3738 hda_nid_t *dac;
3739 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003740 if (!is_in_dac_nids(spec, *dac) &&
3741 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003742 snd_hda_codec_write_cache(codec, *dac, 0,
3743 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3744}
3745
Mattc7d4b2f2005-06-27 14:59:41 +02003746static int stac92xx_init(struct hda_codec *codec)
3747{
3748 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003749 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay45a6ac12008-10-15 14:45:38 -04003750 int i, err;
Mattc7d4b2f2005-06-27 14:59:41 +02003751
Mattc7d4b2f2005-06-27 14:59:41 +02003752 snd_hda_sequence_write(codec, spec->init);
3753
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003754 /* power down adcs initially */
3755 if (spec->powerdown_adcs)
3756 for (i = 0; i < spec->num_adcs; i++)
3757 snd_hda_codec_write_cache(codec,
3758 spec->adc_nids[i], 0,
3759 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003760 /* set up pins */
3761 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003762 /* Enable unsolicited responses on the HP widget */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003763 for (i = 0; i < cfg->hp_outs; i++) {
3764 int type = SND_JACK_HEADPHONE;
3765 hda_nid_t nid = cfg->hp_pins[i];
3766 enable_pin_detect(codec, nid, STAC_HP_EVENT | nid);
3767 /* jack detection */
3768 if (cfg->hp_outs == i)
3769 type |= SND_JACK_LINEOUT;
3770 err = stac92xx_add_jack(codec, nid, type);
3771 if (err < 0)
3772 return err;
3773
3774 }
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003775 /* force to enable the first line-out; the others are set up
3776 * in unsol_event
3777 */
3778 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003779 AC_PINCTL_OUT_EN);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003780 /* fake event to set up pins */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003781 codec->patch_ops.unsol_event(codec,
3782 (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003783 } else {
3784 stac92xx_auto_init_multi_out(codec);
3785 stac92xx_auto_init_hp_out(codec);
3786 }
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003787 for (i = 0; i < cfg->line_outs; i++) {
3788 err = stac92xx_add_jack(codec,
3789 cfg->line_out_pins[i], SND_JACK_LINEOUT);
3790 if (err < 0)
3791 return err;
3792 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003793 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003794 hda_nid_t nid = cfg->input_pins[i];
3795 if (nid) {
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01003796 unsigned int pinctl;
3797 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
3798 /* for mic pins, force to initialize */
3799 pinctl = stac92xx_get_vref(codec, nid);
3800 } else {
3801 pinctl = snd_hda_codec_read(codec, nid, 0,
3802 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3803 /* if PINCTL already set then skip */
3804 if (pinctl & AC_PINCTL_IN_EN)
3805 continue;
3806 }
3807 pinctl |= AC_PINCTL_IN_EN;
Takashi Iwaic960a032006-03-23 17:06:28 +01003808 stac92xx_auto_set_pinctl(codec, nid, pinctl);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003809 err = stac92xx_add_jack(codec, nid,
3810 SND_JACK_MICROPHONE);
3811 if (err < 0)
3812 return err;
3813 enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid);
Takashi Iwaic960a032006-03-23 17:06:28 +01003814 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003815 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003816 for (i = 0; i < spec->num_dmics; i++)
3817 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3818 AC_PINCTL_IN_EN);
3819 for (i = 0; i < spec->num_pwrs; i++) {
3820 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3821 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3822 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3823 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003824 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3825 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003826 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003827 /* outputs are only ports capable of power management
3828 * any attempts on powering down a input port cause the
3829 * referenced VREF to act quirky.
3830 */
3831 if (pinctl & AC_PINCTL_IN_EN)
3832 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003833 /* skip any ports that don't have jacks since presence
3834 * detection is useless */
3835 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003836 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003837 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3838 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3839 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003840 if (spec->dac_list)
3841 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003842 if (cfg->dig_out_pin)
3843 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3844 AC_PINCTL_OUT_EN);
3845 if (cfg->dig_in_pin)
3846 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3847 AC_PINCTL_IN_EN);
3848
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003849 stac_gpio_set(codec, spec->gpio_mask,
3850 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003851
Mattc7d4b2f2005-06-27 14:59:41 +02003852 return 0;
3853}
3854
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003855static void stac92xx_free_jacks(struct hda_codec *codec)
3856{
3857 struct sigmatel_spec *spec = codec->spec;
3858 if (spec->jacks.list) {
3859 struct sigmatel_jack *jacks = spec->jacks.list;
3860 int i;
3861 for (i = 0; i < spec->jacks.used; i++)
3862 snd_device_free(codec->bus->card, &jacks[i].jack);
3863 }
3864 snd_array_free(&spec->jacks);
3865}
3866
Takashi Iwai603c4012008-07-30 15:01:44 +02003867static void stac92xx_free_kctls(struct hda_codec *codec)
3868{
3869 struct sigmatel_spec *spec = codec->spec;
3870
3871 if (spec->kctls.list) {
3872 struct snd_kcontrol_new *kctl = spec->kctls.list;
3873 int i;
3874 for (i = 0; i < spec->kctls.used; i++)
3875 kfree(kctl[i].name);
3876 }
3877 snd_array_free(&spec->kctls);
3878}
3879
Matt2f2f4252005-04-13 14:45:30 +02003880static void stac92xx_free(struct hda_codec *codec)
3881{
Mattc7d4b2f2005-06-27 14:59:41 +02003882 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003883
3884 if (! spec)
3885 return;
3886
Richard Fish11b44bb2006-08-23 18:31:34 +02003887 if (spec->bios_pin_configs)
3888 kfree(spec->bios_pin_configs);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04003889 stac92xx_free_jacks(codec);
3890 snd_array_free(&spec->events);
Richard Fish11b44bb2006-08-23 18:31:34 +02003891
Mattc7d4b2f2005-06-27 14:59:41 +02003892 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003893 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003894}
3895
Matt4e550962005-07-04 17:51:39 +02003896static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3897 unsigned int flag)
3898{
3899 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3900 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02003901
Takashi Iwaif9acba42007-05-29 18:01:06 +02003902 if (pin_ctl & AC_PINCTL_IN_EN) {
3903 /*
3904 * we need to check the current set-up direction of
3905 * shared input pins since they can be switched via
3906 * "xxx as Output" mixer switch
3907 */
3908 struct sigmatel_spec *spec = codec->spec;
3909 struct auto_pin_cfg *cfg = &spec->autocfg;
3910 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3911 spec->line_switch) ||
3912 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3913 spec->mic_switch))
3914 return;
3915 }
3916
Steve Longerbeam7b043892007-05-03 20:50:03 +02003917 /* if setting pin direction bits, clear the current
3918 direction bits first */
3919 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3920 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3921
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003922 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003923 AC_VERB_SET_PIN_WIDGET_CONTROL,
3924 pin_ctl | flag);
3925}
3926
3927static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3928 unsigned int flag)
3929{
3930 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3931 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003932 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003933 AC_VERB_SET_PIN_WIDGET_CONTROL,
3934 pin_ctl & ~flag);
3935}
3936
Jiang Zhe40c1d302007-11-12 13:05:16 +01003937static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003938{
3939 if (!nid)
3940 return 0;
3941 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003942 & (1 << 31)) {
3943 unsigned int pinctl;
3944 pinctl = snd_hda_codec_read(codec, nid, 0,
3945 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3946 if (pinctl & AC_PINCTL_IN_EN)
3947 return 0; /* mic- or line-input */
3948 else
3949 return 1; /* HP-output */
3950 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003951 return 0;
3952}
3953
Takashi Iwaid7a89432008-11-12 09:48:04 +01003954/* return non-zero if the hp-pin of the given array index isn't
3955 * a jack-detection target
3956 */
3957static int no_hp_sensing(struct sigmatel_spec *spec, int i)
3958{
3959 struct auto_pin_cfg *cfg = &spec->autocfg;
3960
3961 /* ignore sensing of shared line and mic jacks */
3962 if (spec->line_switch &&
3963 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
3964 return 1;
3965 if (spec->mic_switch &&
3966 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
3967 return 1;
3968 /* ignore if the pin is set as line-out */
3969 if (cfg->hp_pins[i] == spec->hp_switch)
3970 return 1;
3971 return 0;
3972}
3973
Takashi Iwai314634b2006-09-21 11:56:18 +02003974static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003975{
3976 struct sigmatel_spec *spec = codec->spec;
3977 struct auto_pin_cfg *cfg = &spec->autocfg;
3978 int i, presence;
3979
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003980 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003981 if (spec->gpio_mute)
3982 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3983 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3984
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003985 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003986 if (presence)
3987 break;
Takashi Iwaid7a89432008-11-12 09:48:04 +01003988 if (no_hp_sensing(spec, i))
3989 continue;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01003990 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003991 }
Matt4e550962005-07-04 17:51:39 +02003992
3993 if (presence) {
Takashi Iwaid7a89432008-11-12 09:48:04 +01003994 /* disable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003995 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01003996 stac92xx_reset_pinctl(codec, spec->hp_switch,
3997 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003998 for (i = 0; i < cfg->line_outs; i++)
3999 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
4000 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004001 for (i = 0; i < cfg->speaker_outs; i++)
4002 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
4003 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004004 if (spec->eapd_mask)
4005 stac_gpio_set(codec, spec->gpio_mask,
4006 spec->gpio_dir, spec->gpio_data &
4007 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02004008 } else {
Takashi Iwaid7a89432008-11-12 09:48:04 +01004009 /* enable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02004010 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01004011 stac92xx_set_pinctl(codec, spec->hp_switch,
4012 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02004013 for (i = 0; i < cfg->line_outs; i++)
4014 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
4015 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004016 for (i = 0; i < cfg->speaker_outs; i++)
4017 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
4018 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004019 if (spec->eapd_mask)
4020 stac_gpio_set(codec, spec->gpio_mask,
4021 spec->gpio_dir, spec->gpio_data |
4022 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02004023 }
Takashi Iwaid7a89432008-11-12 09:48:04 +01004024 /* toggle hp outs */
4025 for (i = 0; i < cfg->hp_outs; i++) {
4026 unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
4027 if (no_hp_sensing(spec, i))
4028 continue;
4029 if (presence)
4030 stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
4031 else
4032 stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
4033 }
Matt4e550962005-07-04 17:51:39 +02004034}
4035
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004036static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
4037{
4038 struct sigmatel_spec *spec = codec->spec;
4039 hda_nid_t nid = spec->pwr_nids[idx];
4040 int presence, val;
4041 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
4042 & 0x000000ff;
4043 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004044
4045 /* several codecs have two power down bits */
4046 if (spec->pwr_mapping)
4047 idx = spec->pwr_mapping[idx];
4048 else
4049 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004050
4051 if (presence)
4052 val &= ~idx;
4053 else
4054 val |= idx;
4055
4056 /* power down unused output ports */
4057 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004058}
4059
4060static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
4061{
4062 struct sigmatel_spec *spec = codec->spec;
4063 struct sigmatel_jack *jacks = spec->jacks.list;
4064
4065 if (jacks) {
4066 int i;
4067 for (i = 0; i < spec->jacks.used; i++) {
4068 if (jacks->nid == nid) {
4069 unsigned int pin_ctl =
4070 snd_hda_codec_read(codec, nid,
4071 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
4072 0x00);
4073 int type = jacks->type;
4074 if (type == (SND_JACK_LINEOUT
4075 | SND_JACK_HEADPHONE))
4076 type = (pin_ctl & AC_PINCTL_HP_EN)
4077 ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
4078 snd_jack_report(jacks->jack,
4079 get_hp_pin_presence(codec, nid)
4080 ? type : 0);
4081 }
4082 jacks++;
4083 }
4084 }
4085}
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004086
Takashi Iwai314634b2006-09-21 11:56:18 +02004087static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
4088{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004089 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004090 int event = (res >> 26) & 0x70;
4091 int nid = res >> 26 & 0x0f;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004092
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004093 switch (event) {
Takashi Iwai314634b2006-09-21 11:56:18 +02004094 case STAC_HP_EVENT:
4095 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004096 /* fallthru */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004097 case STAC_INSERT_EVENT:
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004098 case STAC_PWR_EVENT:
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004099 if (nid) {
4100 if (spec->num_pwrs > 0)
4101 stac92xx_pin_sense(codec, nid);
4102 stac92xx_report_jack(codec, nid);
4103 }
Matthew Ranostay72474be2008-10-09 09:32:17 -04004104 break;
4105 case STAC_VREF_EVENT: {
4106 int data = snd_hda_codec_read(codec, codec->afg, 0,
4107 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004108 int idx = stac92xx_event_data(codec, nid);
Matthew Ranostay72474be2008-10-09 09:32:17 -04004109 /* toggle VREF state based on GPIOx status */
4110 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
4111 !!(data & (1 << idx)));
4112 break;
4113 }
Takashi Iwai314634b2006-09-21 11:56:18 +02004114 }
4115}
4116
Takashi Iwaicb53c622007-08-10 17:21:45 +02004117#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004118static int stac92xx_resume(struct hda_codec *codec)
4119{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004120 struct sigmatel_spec *spec = codec->spec;
4121
Richard Fish11b44bb2006-08-23 18:31:34 +02004122 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004123 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004124 stac_gpio_set(codec, spec->gpio_mask,
4125 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004126 snd_hda_codec_resume_amp(codec);
4127 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004128 /* power down inactive DACs */
4129 if (spec->dac_list)
4130 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02004131 /* invoke unsolicited event to reset the HP state */
4132 if (spec->hp_detect)
4133 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02004134 return 0;
4135}
4136#endif
4137
Matt2f2f4252005-04-13 14:45:30 +02004138static struct hda_codec_ops stac92xx_patch_ops = {
4139 .build_controls = stac92xx_build_controls,
4140 .build_pcms = stac92xx_build_pcms,
4141 .init = stac92xx_init,
4142 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02004143 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004144#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02004145 .resume = stac92xx_resume,
4146#endif
Matt2f2f4252005-04-13 14:45:30 +02004147};
4148
4149static int patch_stac9200(struct hda_codec *codec)
4150{
4151 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004152 int err;
Matt2f2f4252005-04-13 14:45:30 +02004153
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004154 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004155 if (spec == NULL)
4156 return -ENOMEM;
4157
4158 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004159 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004160 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004161 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
4162 stac9200_models,
4163 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02004164 if (spec->board_config < 0) {
4165 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
4166 err = stac92xx_save_bios_config_regs(codec);
4167 if (err < 0) {
4168 stac92xx_free(codec);
4169 return err;
4170 }
4171 spec->pin_configs = spec->bios_pin_configs;
4172 } else {
Matt Porter403d1942005-11-29 15:00:51 +01004173 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
4174 stac92xx_set_config_regs(codec);
4175 }
Matt2f2f4252005-04-13 14:45:30 +02004176
4177 spec->multiout.max_channels = 2;
4178 spec->multiout.num_dacs = 1;
4179 spec->multiout.dac_nids = stac9200_dac_nids;
4180 spec->adc_nids = stac9200_adc_nids;
4181 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02004182 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02004183 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004184 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004185 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004186
Tobin Davisbf277782008-02-03 20:31:47 +01004187 if (spec->board_config == STAC_9200_GATEWAY ||
4188 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02004189 spec->init = stac9200_eapd_init;
4190 else
4191 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004192 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004193
Takashi Iwai117f2572008-03-18 09:53:23 +01004194 if (spec->board_config == STAC_9200_PANASONIC) {
4195 spec->gpio_mask = spec->gpio_dir = 0x09;
4196 spec->gpio_data = 0x00;
4197 }
4198
Mattc7d4b2f2005-06-27 14:59:41 +02004199 err = stac9200_parse_auto_config(codec);
4200 if (err < 0) {
4201 stac92xx_free(codec);
4202 return err;
4203 }
Matt2f2f4252005-04-13 14:45:30 +02004204
4205 codec->patch_ops = stac92xx_patch_ops;
4206
4207 return 0;
4208}
4209
Tobin Davis8e21c342007-01-08 11:04:17 +01004210static int patch_stac925x(struct hda_codec *codec)
4211{
4212 struct sigmatel_spec *spec;
4213 int err;
4214
4215 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4216 if (spec == NULL)
4217 return -ENOMEM;
4218
4219 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004220 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01004221 spec->pin_nids = stac925x_pin_nids;
4222 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
4223 stac925x_models,
4224 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004225 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01004226 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02004227 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
4228 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01004229 err = stac92xx_save_bios_config_regs(codec);
4230 if (err < 0) {
4231 stac92xx_free(codec);
4232 return err;
4233 }
4234 spec->pin_configs = spec->bios_pin_configs;
4235 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
4236 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
4237 stac92xx_set_config_regs(codec);
4238 }
4239
4240 spec->multiout.max_channels = 2;
4241 spec->multiout.num_dacs = 1;
4242 spec->multiout.dac_nids = stac925x_dac_nids;
4243 spec->adc_nids = stac925x_adc_nids;
4244 spec->mux_nids = stac925x_mux_nids;
4245 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004246 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004247 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02004248 switch (codec->vendor_id) {
4249 case 0x83847632: /* STAC9202 */
4250 case 0x83847633: /* STAC9202D */
4251 case 0x83847636: /* STAC9251 */
4252 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02004253 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02004254 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004255 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
4256 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02004257 break;
4258 default:
4259 spec->num_dmics = 0;
4260 break;
4261 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004262
4263 spec->init = stac925x_core_init;
4264 spec->mixer = stac925x_mixer;
4265
4266 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004267 if (!err) {
4268 if (spec->board_config < 0) {
4269 printk(KERN_WARNING "hda_codec: No auto-config is "
4270 "available, default to model=ref\n");
4271 spec->board_config = STAC_925x_REF;
4272 goto again;
4273 }
4274 err = -EINVAL;
4275 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004276 if (err < 0) {
4277 stac92xx_free(codec);
4278 return err;
4279 }
4280
4281 codec->patch_ops = stac92xx_patch_ops;
4282
4283 return 0;
4284}
4285
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004286static struct hda_input_mux stac92hd73xx_dmux = {
4287 .num_items = 4,
4288 .items = {
4289 { "Analog Inputs", 0x0b },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004290 { "Digital Mic 1", 0x09 },
4291 { "Digital Mic 2", 0x0a },
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004292 { "CD", 0x08 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004293 }
4294};
4295
4296static int patch_stac92hd73xx(struct hda_codec *codec)
4297{
4298 struct sigmatel_spec *spec;
4299 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
4300 int err = 0;
4301
4302 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4303 if (spec == NULL)
4304 return -ENOMEM;
4305
4306 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02004307 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004308 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
4309 spec->pin_nids = stac92hd73xx_pin_nids;
4310 spec->board_config = snd_hda_check_board_config(codec,
4311 STAC_92HD73XX_MODELS,
4312 stac92hd73xx_models,
4313 stac92hd73xx_cfg_tbl);
4314again:
4315 if (spec->board_config < 0) {
4316 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4317 " STAC92HD73XX, using BIOS defaults\n");
4318 err = stac92xx_save_bios_config_regs(codec);
4319 if (err < 0) {
4320 stac92xx_free(codec);
4321 return err;
4322 }
4323 spec->pin_configs = spec->bios_pin_configs;
4324 } else {
4325 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
4326 stac92xx_set_config_regs(codec);
4327 }
4328
4329 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
4330 conn, STAC92HD73_DAC_COUNT + 2) - 1;
4331
4332 if (spec->multiout.num_dacs < 0) {
4333 printk(KERN_WARNING "hda_codec: Could not determine "
4334 "number of channels defaulting to DAC count\n");
4335 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
4336 }
4337
4338 switch (spec->multiout.num_dacs) {
4339 case 0x3: /* 6 Channel */
4340 spec->mixer = stac92hd73xx_6ch_mixer;
4341 spec->init = stac92hd73xx_6ch_core_init;
4342 break;
4343 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004344 spec->mixer = stac92hd73xx_8ch_mixer;
4345 spec->init = stac92hd73xx_8ch_core_init;
4346 break;
4347 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004348 spec->mixer = stac92hd73xx_10ch_mixer;
4349 spec->init = stac92hd73xx_10ch_core_init;
4350 };
4351
4352 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
4353 spec->aloopback_mask = 0x01;
4354 spec->aloopback_shift = 8;
4355
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004356 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004357 spec->mux_nids = stac92hd73xx_mux_nids;
4358 spec->adc_nids = stac92hd73xx_adc_nids;
4359 spec->dmic_nids = stac92hd73xx_dmic_nids;
4360 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004361 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostay89385032008-09-11 09:49:39 -04004362 spec->amp_nids = stac92hd73xx_amp_nids;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004363 spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004364
4365 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
4366 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004367 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004368 memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
4369 sizeof(stac92hd73xx_dmux));
4370
Matthew Ranostaya7662642008-02-21 07:51:14 +01004371 switch (spec->board_config) {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004372 case STAC_DELL_EQ:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004373 spec->init = dell_eq_core_init;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004374 /* fallthru */
4375 case STAC_DELL_M6:
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004376 spec->num_smuxes = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004377 spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
4378 spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
4379 spec->num_amps = 1;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05004380
4381 if (!spec->init)
4382 spec->init = dell_m6_core_init;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004383 switch (codec->subsystem_id) {
4384 case 0x1028025e: /* Analog Mics */
4385 case 0x1028025f:
4386 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4387 spec->num_dmics = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004388 spec->private_dimux.num_items = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004389 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01004390 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004391 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004392 case 0x10280254:
4393 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01004394 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4395 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004396 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004397 break;
4398 case 0x10280256: /* Both */
4399 case 0x10280057:
4400 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4401 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4402 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004403 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004404 break;
4405 }
4406 break;
4407 default:
4408 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004409 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaya7662642008-02-21 07:51:14 +01004410 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004411 if (spec->board_config > STAC_92HD73XX_REF) {
4412 /* GPIO0 High = Enable EAPD */
4413 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
4414 spec->gpio_data = 0x01;
4415 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004416 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004417
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004418 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
4419 spec->pwr_nids = stac92hd73xx_pwr_nids;
4420
Matthew Ranostayd9737752008-09-07 12:03:41 +02004421 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004422
4423 if (!err) {
4424 if (spec->board_config < 0) {
4425 printk(KERN_WARNING "hda_codec: No auto-config is "
4426 "available, default to model=ref\n");
4427 spec->board_config = STAC_92HD73XX_REF;
4428 goto again;
4429 }
4430 err = -EINVAL;
4431 }
4432
4433 if (err < 0) {
4434 stac92xx_free(codec);
4435 return err;
4436 }
4437
4438 codec->patch_ops = stac92xx_patch_ops;
4439
4440 return 0;
4441}
4442
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004443static struct hda_input_mux stac92hd83xxx_dmux = {
4444 .num_items = 3,
4445 .items = {
4446 { "Analog Inputs", 0x03 },
4447 { "Digital Mic 1", 0x04 },
4448 { "Digital Mic 2", 0x05 },
4449 }
4450};
4451
4452static int patch_stac92hd83xxx(struct hda_codec *codec)
4453{
4454 struct sigmatel_spec *spec;
4455 int err;
4456
4457 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4458 if (spec == NULL)
4459 return -ENOMEM;
4460
4461 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004462 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004463 spec->mono_nid = 0x19;
4464 spec->digbeep_nid = 0x21;
4465 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4466 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4467 spec->adc_nids = stac92hd83xxx_adc_nids;
4468 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4469 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4470 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4471 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4472
4473 spec->init = stac92hd83xxx_core_init;
4474 switch (codec->vendor_id) {
4475 case 0x111d7605:
4476 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4477 break;
4478 default:
4479 spec->num_pwrs--;
4480 spec->init++; /* switch to config #2 */
4481 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4482 }
4483
4484 spec->mixer = stac92hd83xxx_mixer;
4485 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4486 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4487 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4488 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4489 spec->dinput_mux = &stac92hd83xxx_dmux;
4490 spec->pin_nids = stac92hd83xxx_pin_nids;
4491 spec->board_config = snd_hda_check_board_config(codec,
4492 STAC_92HD83XXX_MODELS,
4493 stac92hd83xxx_models,
4494 stac92hd83xxx_cfg_tbl);
4495again:
4496 if (spec->board_config < 0) {
4497 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4498 " STAC92HD83XXX, using BIOS defaults\n");
4499 err = stac92xx_save_bios_config_regs(codec);
4500 if (err < 0) {
4501 stac92xx_free(codec);
4502 return err;
4503 }
4504 spec->pin_configs = spec->bios_pin_configs;
4505 } else {
4506 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4507 stac92xx_set_config_regs(codec);
4508 }
4509
4510 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4511 if (!err) {
4512 if (spec->board_config < 0) {
4513 printk(KERN_WARNING "hda_codec: No auto-config is "
4514 "available, default to model=ref\n");
4515 spec->board_config = STAC_92HD83XXX_REF;
4516 goto again;
4517 }
4518 err = -EINVAL;
4519 }
4520
4521 if (err < 0) {
4522 stac92xx_free(codec);
4523 return err;
4524 }
4525
4526 codec->patch_ops = stac92xx_patch_ops;
4527
4528 return 0;
4529}
4530
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004531#ifdef SND_HDA_NEEDS_RESUME
4532static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4533{
4534 struct sigmatel_spec *spec = codec->spec;
4535 int i;
4536 snd_hda_codec_write_cache(codec, codec->afg, 0,
4537 AC_VERB_SET_POWER_STATE, pwr);
4538
4539 msleep(1);
4540 for (i = 0; i < spec->num_adcs; i++) {
4541 snd_hda_codec_write_cache(codec,
4542 spec->adc_nids[i], 0,
4543 AC_VERB_SET_POWER_STATE, pwr);
4544 }
4545};
4546
4547static int stac92hd71xx_resume(struct hda_codec *codec)
4548{
4549 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4550 return stac92xx_resume(codec);
4551}
4552
4553static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4554{
4555 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4556 return 0;
4557};
4558
4559#endif
4560
4561static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4562 .build_controls = stac92xx_build_controls,
4563 .build_pcms = stac92xx_build_pcms,
4564 .init = stac92xx_init,
4565 .free = stac92xx_free,
4566 .unsol_event = stac92xx_unsol_event,
4567#ifdef SND_HDA_NEEDS_RESUME
4568 .resume = stac92hd71xx_resume,
4569 .suspend = stac92hd71xx_suspend,
4570#endif
4571};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004572
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004573static struct hda_input_mux stac92hd71bxx_dmux = {
4574 .num_items = 4,
4575 .items = {
4576 { "Analog Inputs", 0x00 },
4577 { "Mixer", 0x01 },
4578 { "Digital Mic 1", 0x02 },
4579 { "Digital Mic 2", 0x03 },
4580 }
4581};
4582
Matthew Ranostaye035b842007-11-06 11:53:55 +01004583static int patch_stac92hd71bxx(struct hda_codec *codec)
4584{
4585 struct sigmatel_spec *spec;
4586 int err = 0;
4587
4588 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4589 if (spec == NULL)
4590 return -ENOMEM;
4591
4592 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004593 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004594 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004595 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004596 spec->pin_nids = stac92hd71bxx_pin_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004597 memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
4598 sizeof(stac92hd71bxx_dmux));
Matthew Ranostaye035b842007-11-06 11:53:55 +01004599 spec->board_config = snd_hda_check_board_config(codec,
4600 STAC_92HD71BXX_MODELS,
4601 stac92hd71bxx_models,
4602 stac92hd71bxx_cfg_tbl);
4603again:
4604 if (spec->board_config < 0) {
4605 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4606 " STAC92HD71BXX, using BIOS defaults\n");
4607 err = stac92xx_save_bios_config_regs(codec);
4608 if (err < 0) {
4609 stac92xx_free(codec);
4610 return err;
4611 }
4612 spec->pin_configs = spec->bios_pin_configs;
4613 } else {
4614 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4615 stac92xx_set_config_regs(codec);
4616 }
4617
Matthew Ranostay541eee82007-12-14 12:08:04 +01004618 switch (codec->vendor_id) {
4619 case 0x111d76b6: /* 4 Port without Analog Mixer */
4620 case 0x111d76b7:
4621 case 0x111d76b4: /* 6 Port without Analog Mixer */
4622 case 0x111d76b5:
4623 spec->mixer = stac92hd71bxx_mixer;
4624 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004625 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004626 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004627 case 0x111d7608: /* 5 Port with Analog Mixer */
Matthew Ranostay72474be2008-10-09 09:32:17 -04004628 switch (codec->subsystem_id) {
4629 case 0x103c361a:
4630 /* Enable VREF power saving on GPIO1 detect */
4631 snd_hda_codec_write(codec, codec->afg, 0,
4632 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4633 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004634 AC_VERB_SET_UNSOLICITED_ENABLE,
4635 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
4636 err = stac92xx_add_event(spec, codec->afg, 0x02);
4637 if (err < 0)
4638 return err;
Matthew Ranostay72474be2008-10-09 09:32:17 -04004639 spec->gpio_mask |= 0x02;
4640 break;
4641 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004642 if ((codec->revision_id & 0xf) == 0 ||
4643 (codec->revision_id & 0xf) == 1) {
4644#ifdef SND_HDA_NEEDS_RESUME
4645 codec->patch_ops = stac92hd71bxx_patch_ops;
4646#endif
4647 spec->stream_delay = 40; /* 40 milliseconds */
4648 }
4649
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004650 /* no output amps */
4651 spec->num_pwrs = 0;
4652 spec->mixer = stac92hd71bxx_analog_mixer;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004653 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004654
4655 /* disable VSW */
4656 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4657 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4658 break;
4659 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004660 if ((codec->revision_id & 0xf) == 1) {
4661#ifdef SND_HDA_NEEDS_RESUME
4662 codec->patch_ops = stac92hd71bxx_patch_ops;
4663#endif
4664 spec->stream_delay = 40; /* 40 milliseconds */
4665 }
4666
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004667 /* no output amps */
4668 spec->num_pwrs = 0;
4669 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004670 default:
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004671 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004672 spec->mixer = stac92hd71bxx_analog_mixer;
4673 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004674 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004675 }
4676
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004677 spec->aloopback_mask = 0x50;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004678 spec->aloopback_shift = 0;
4679
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004680 if (spec->board_config > STAC_92HD71BXX_REF) {
4681 /* GPIO0 = EAPD */
4682 spec->gpio_mask = 0x01;
4683 spec->gpio_dir = 0x01;
4684 spec->gpio_data = 0x01;
4685 }
Matthew Ranostaye035b842007-11-06 11:53:55 +01004686
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004687 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004688 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004689 spec->mux_nids = stac92hd71bxx_mux_nids;
4690 spec->adc_nids = stac92hd71bxx_adc_nids;
4691 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004692 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004693 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004694 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004695
4696 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4697 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004698
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004699 switch (spec->board_config) {
4700 case STAC_HP_M4:
4701 spec->num_dmics = 0;
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004702 spec->num_smuxes = 0;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004703 spec->num_dmuxes = 0;
4704
4705 /* enable internal microphone */
Matthew Ranostayb9aea712008-10-09 08:37:28 -04004706 stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
4707 stac92xx_auto_set_pinctl(codec, 0x0e,
4708 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004709 break;
4710 default:
4711 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4712 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4713 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4714 };
4715
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004716 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004717 spec->multiout.hp_nid = 0x11;
4718 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04004719 if (spec->dinput_mux)
4720 spec->private_dimux.num_items +=
4721 spec->num_dmics -
4722 (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004723
4724 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4725 if (!err) {
4726 if (spec->board_config < 0) {
4727 printk(KERN_WARNING "hda_codec: No auto-config is "
4728 "available, default to model=ref\n");
4729 spec->board_config = STAC_92HD71BXX_REF;
4730 goto again;
4731 }
4732 err = -EINVAL;
4733 }
4734
4735 if (err < 0) {
4736 stac92xx_free(codec);
4737 return err;
4738 }
4739
Matthew Ranostaye035b842007-11-06 11:53:55 +01004740 return 0;
4741};
4742
Matt2f2f4252005-04-13 14:45:30 +02004743static int patch_stac922x(struct hda_codec *codec)
4744{
4745 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004746 int err;
Matt2f2f4252005-04-13 14:45:30 +02004747
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004748 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004749 if (spec == NULL)
4750 return -ENOMEM;
4751
4752 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004753 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004754 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004755 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4756 stac922x_models,
4757 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004758 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004759 spec->gpio_mask = spec->gpio_dir = 0x03;
4760 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004761 /* Intel Macs have all same PCI SSID, so we need to check
4762 * codec SSID to distinguish the exact models
4763 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004764 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004765 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004766
4767 case 0x106b0800:
4768 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004769 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004770 case 0x106b0600:
4771 case 0x106b0700:
4772 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004773 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004774 case 0x106b0e00:
4775 case 0x106b0f00:
4776 case 0x106b1600:
4777 case 0x106b1700:
4778 case 0x106b0200:
4779 case 0x106b1e00:
4780 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004781 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004782 case 0x106b1a00:
4783 case 0x00000100:
4784 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004785 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004786 case 0x106b0a00:
4787 case 0x106b2200:
4788 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004789 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004790 default:
4791 spec->board_config = STAC_INTEL_MAC_V3;
4792 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004793 }
4794 }
4795
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004796 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004797 if (spec->board_config < 0) {
4798 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4799 "using BIOS defaults\n");
4800 err = stac92xx_save_bios_config_regs(codec);
4801 if (err < 0) {
4802 stac92xx_free(codec);
4803 return err;
4804 }
4805 spec->pin_configs = spec->bios_pin_configs;
4806 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004807 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4808 stac92xx_set_config_regs(codec);
4809 }
Matt2f2f4252005-04-13 14:45:30 +02004810
Matt2f2f4252005-04-13 14:45:30 +02004811 spec->adc_nids = stac922x_adc_nids;
4812 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004813 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004814 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004815 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004816 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004817
4818 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004819 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004820
4821 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004822
Matt Porter3cc08dc2006-01-23 15:27:49 +01004823 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004824 if (!err) {
4825 if (spec->board_config < 0) {
4826 printk(KERN_WARNING "hda_codec: No auto-config is "
4827 "available, default to model=ref\n");
4828 spec->board_config = STAC_D945_REF;
4829 goto again;
4830 }
4831 err = -EINVAL;
4832 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004833 if (err < 0) {
4834 stac92xx_free(codec);
4835 return err;
4836 }
4837
4838 codec->patch_ops = stac92xx_patch_ops;
4839
Takashi Iwai807a46362007-05-29 19:01:37 +02004840 /* Fix Mux capture level; max to 2 */
4841 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4842 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4843 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4844 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4845 (0 << AC_AMPCAP_MUTE_SHIFT));
4846
Matt Porter3cc08dc2006-01-23 15:27:49 +01004847 return 0;
4848}
4849
4850static int patch_stac927x(struct hda_codec *codec)
4851{
4852 struct sigmatel_spec *spec;
4853 int err;
4854
4855 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4856 if (spec == NULL)
4857 return -ENOMEM;
4858
4859 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004860 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004861 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004862 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4863 stac927x_models,
4864 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004865 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004866 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4867 if (spec->board_config < 0)
4868 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4869 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004870 err = stac92xx_save_bios_config_regs(codec);
4871 if (err < 0) {
4872 stac92xx_free(codec);
4873 return err;
4874 }
4875 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004876 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004877 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4878 stac92xx_set_config_regs(codec);
4879 }
4880
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004881 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004882 spec->adc_nids = stac927x_adc_nids;
4883 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4884 spec->mux_nids = stac927x_mux_nids;
4885 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004886 spec->smux_nids = stac927x_smux_nids;
4887 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04004888 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004889 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004890 spec->multiout.dac_nids = spec->dac_nids;
4891
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004892 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004893 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004894 case STAC_D965_5ST:
4895 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004896 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004897 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004898 spec->num_dmics = 0;
4899
Tobin Davis93ed1502006-09-01 21:03:12 +02004900 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004901 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004902 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004903 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004904 switch (codec->subsystem_id) {
4905 case 0x10280209:
4906 case 0x1028022e:
4907 /* correct the device field to SPDIF out */
4908 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4909 break;
4910 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004911 /* configure the analog microphone on some laptops */
4912 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004913 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004914 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004915 /* correct the front input jack as a mic */
4916 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4917 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004918 case STAC_DELL_3ST:
4919 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004920 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004921 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004922 spec->dmic_nids = stac927x_dmic_nids;
4923 spec->num_dmics = STAC927X_NUM_DMICS;
4924
Tobin Davis93ed1502006-09-01 21:03:12 +02004925 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004926 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004927 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004928 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004929 break;
4930 default:
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004931 if (spec->board_config > STAC_D965_REF) {
4932 /* GPIO0 High = Enable EAPD */
4933 spec->eapd_mask = spec->gpio_mask = 0x01;
4934 spec->gpio_dir = spec->gpio_data = 0x01;
4935 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004936 spec->num_dmics = 0;
4937
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004938 spec->init = stac927x_core_init;
4939 spec->mixer = stac927x_mixer;
4940 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004941
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004942 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004943 spec->aloopback_mask = 0x40;
4944 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004945
Matt Porter3cc08dc2006-01-23 15:27:49 +01004946 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004947 if (!err) {
4948 if (spec->board_config < 0) {
4949 printk(KERN_WARNING "hda_codec: No auto-config is "
4950 "available, default to model=ref\n");
4951 spec->board_config = STAC_D965_REF;
4952 goto again;
4953 }
4954 err = -EINVAL;
4955 }
Mattc7d4b2f2005-06-27 14:59:41 +02004956 if (err < 0) {
4957 stac92xx_free(codec);
4958 return err;
4959 }
Matt2f2f4252005-04-13 14:45:30 +02004960
4961 codec->patch_ops = stac92xx_patch_ops;
4962
Takashi Iwai52987652008-01-16 16:09:47 +01004963 /*
4964 * !!FIXME!!
4965 * The STAC927x seem to require fairly long delays for certain
4966 * command sequences. With too short delays (even if the answer
4967 * is set to RIRB properly), it results in the silence output
4968 * on some hardwares like Dell.
4969 *
4970 * The below flag enables the longer delay (see get_response
4971 * in hda_intel.c).
4972 */
4973 codec->bus->needs_damn_long_delay = 1;
4974
Matt2f2f4252005-04-13 14:45:30 +02004975 return 0;
4976}
4977
Matt Porterf3302a52006-07-31 12:49:34 +02004978static int patch_stac9205(struct hda_codec *codec)
4979{
4980 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004981 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004982
4983 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4984 if (spec == NULL)
4985 return -ENOMEM;
4986
4987 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004988 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004989 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004990 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4991 stac9205_models,
4992 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004993 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004994 if (spec->board_config < 0) {
4995 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4996 err = stac92xx_save_bios_config_regs(codec);
4997 if (err < 0) {
4998 stac92xx_free(codec);
4999 return err;
5000 }
5001 spec->pin_configs = spec->bios_pin_configs;
5002 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02005003 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
5004 stac92xx_set_config_regs(codec);
5005 }
5006
Matthew Ranostay1cd22242008-07-18 18:20:52 +02005007 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02005008 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005009 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02005010 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01005011 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02005012 spec->smux_nids = stac9205_smux_nids;
5013 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02005014 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02005015 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005016 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01005017 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005018 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02005019
5020 spec->init = stac9205_core_init;
5021 spec->mixer = stac9205_mixer;
5022
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005023 spec->aloopback_mask = 0x40;
5024 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02005025 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02005026
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005027 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005028 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02005029 /* Enable SPDIF in/out */
5030 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
5031 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01005032
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005033 /* Enable unsol response for GPIO4/Dock HP connection */
5034 snd_hda_codec_write(codec, codec->afg, 0,
5035 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
5036 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04005037 AC_VERB_SET_UNSOLICITED_ENABLE,
5038 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
5039 err = stac92xx_add_event(spec, codec->afg, 0x01);
5040 if (err < 0)
5041 return err;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005042
5043 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005044 spec->eapd_mask = 0x01;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005045 spec->gpio_mask = 0x1b;
5046 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01005047 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005048 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02005049 */
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005050 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005051 break;
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04005052 case STAC_9205_REF:
5053 /* SPDIF-In enabled */
5054 break;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005055 default:
5056 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02005057 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005058 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02005059 break;
5060 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02005061
Matt Porterf3302a52006-07-31 12:49:34 +02005062 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005063 if (!err) {
5064 if (spec->board_config < 0) {
5065 printk(KERN_WARNING "hda_codec: No auto-config is "
5066 "available, default to model=ref\n");
5067 spec->board_config = STAC_9205_REF;
5068 goto again;
5069 }
5070 err = -EINVAL;
5071 }
Matt Porterf3302a52006-07-31 12:49:34 +02005072 if (err < 0) {
5073 stac92xx_free(codec);
5074 return err;
5075 }
5076
5077 codec->patch_ops = stac92xx_patch_ops;
5078
5079 return 0;
5080}
5081
Matt2f2f4252005-04-13 14:45:30 +02005082/*
Guillaume Munch6d859062006-08-22 17:15:47 +02005083 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01005084 */
5085
Guillaume Munch99ccc562006-08-16 19:35:12 +02005086/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005087static hda_nid_t vaio_dacs[] = { 0x2 };
5088#define VAIO_HP_DAC 0x5
5089static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
5090static hda_nid_t vaio_mux_nids[] = { 0x15 };
5091
5092static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02005093 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01005094 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02005095 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005096 { "Mic Jack", 0x1 },
5097 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01005098 { "PCM", 0x3 },
5099 }
5100};
5101
5102static struct hda_verb vaio_init[] = {
5103 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005104 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01005105 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5106 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5107 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5108 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005109 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01005110 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5111 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5112 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5113 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5114 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5115 {}
5116};
5117
Guillaume Munch6d859062006-08-22 17:15:47 +02005118static struct hda_verb vaio_ar_init[] = {
5119 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
5120 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
5121 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
5122 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
5123/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
5124 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02005125 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02005126 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
5127 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
5128/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
5129 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
5130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
5131 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
5132 {}
5133};
5134
Takashi Iwaidb064e52006-03-16 16:04:58 +01005135static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwai127e82e2008-11-14 14:03:33 +01005136 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
5137 HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
5138 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
5139 HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005140 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5141 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5142 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5143 {
5144 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5145 .name = "Capture Source",
5146 .count = 1,
5147 .info = stac92xx_mux_enum_info,
5148 .get = stac92xx_mux_enum_get,
5149 .put = stac92xx_mux_enum_put,
5150 },
5151 {}
5152};
5153
Guillaume Munch6d859062006-08-22 17:15:47 +02005154static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwai127e82e2008-11-14 14:03:33 +01005155 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT),
5156 HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT),
5157 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT),
5158 HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT),
Guillaume Munch6d859062006-08-22 17:15:47 +02005159 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
5160 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
5161 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
5162 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
5163 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
5164 {
5165 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5166 .name = "Capture Source",
5167 .count = 1,
5168 .info = stac92xx_mux_enum_info,
5169 .get = stac92xx_mux_enum_get,
5170 .put = stac92xx_mux_enum_put,
5171 },
5172 {}
5173};
5174
5175static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01005176 .build_controls = stac92xx_build_controls,
5177 .build_pcms = stac92xx_build_pcms,
5178 .init = stac92xx_init,
5179 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005180#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01005181 .resume = stac92xx_resume,
5182#endif
5183};
5184
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005185static int stac9872_vaio_init(struct hda_codec *codec)
5186{
5187 int err;
5188
5189 err = stac92xx_init(codec);
5190 if (err < 0)
5191 return err;
5192 if (codec->patch_ops.unsol_event)
5193 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
5194 return 0;
5195}
5196
5197static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
5198{
Jiang Zhe40c1d302007-11-12 13:05:16 +01005199 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005200 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5201 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5202 } else {
5203 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
5204 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
5205 }
5206}
5207
5208static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
5209{
5210 switch (res >> 26) {
5211 case STAC_HP_EVENT:
5212 stac9872_vaio_hp_detect(codec, res);
5213 break;
5214 }
5215}
5216
5217static struct hda_codec_ops stac9872_vaio_patch_ops = {
5218 .build_controls = stac92xx_build_controls,
5219 .build_pcms = stac92xx_build_pcms,
5220 .init = stac9872_vaio_init,
5221 .free = stac92xx_free,
5222 .unsol_event = stac9872_vaio_unsol_event,
5223#ifdef CONFIG_PM
5224 .resume = stac92xx_resume,
5225#endif
5226};
5227
Guillaume Munch6d859062006-08-22 17:15:47 +02005228enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
5229 CXD9872RD_VAIO,
5230 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
5231 STAC9872AK_VAIO,
5232 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
5233 STAC9872K_VAIO,
5234 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005235 CXD9872AKD_VAIO,
5236 STAC_9872_MODELS,
5237};
Takashi Iwaidb064e52006-03-16 16:04:58 +01005238
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005239static const char *stac9872_models[STAC_9872_MODELS] = {
5240 [CXD9872RD_VAIO] = "vaio",
5241 [CXD9872AKD_VAIO] = "vaio-ar",
5242};
5243
5244static struct snd_pci_quirk stac9872_cfg_tbl[] = {
5245 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
5246 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
5247 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01005248 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01005249 {}
5250};
5251
Guillaume Munch6d859062006-08-22 17:15:47 +02005252static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01005253{
5254 struct sigmatel_spec *spec;
5255 int board_config;
5256
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005257 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
5258 stac9872_models,
5259 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01005260 if (board_config < 0)
5261 /* unknown config, let generic-parser do its job... */
5262 return snd_hda_parse_generic_codec(codec);
5263
5264 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5265 if (spec == NULL)
5266 return -ENOMEM;
5267
5268 codec->spec = spec;
5269 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02005270 case CXD9872RD_VAIO:
5271 case STAC9872AK_VAIO:
5272 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01005273 spec->mixer = vaio_mixer;
5274 spec->init = vaio_init;
5275 spec->multiout.max_channels = 2;
5276 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5277 spec->multiout.dac_nids = vaio_dacs;
5278 spec->multiout.hp_nid = VAIO_HP_DAC;
5279 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
5280 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005281 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005282 spec->input_mux = &vaio_mux;
5283 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005284 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005285 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02005286
5287 case CXD9872AKD_VAIO:
5288 spec->mixer = vaio_ar_mixer;
5289 spec->init = vaio_ar_init;
5290 spec->multiout.max_channels = 2;
5291 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5292 spec->multiout.dac_nids = vaio_dacs;
5293 spec->multiout.hp_nid = VAIO_HP_DAC;
5294 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005295 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02005296 spec->adc_nids = vaio_adcs;
5297 spec->input_mux = &vaio_mux;
5298 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005299 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02005300 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005301 }
5302
Takashi Iwaidb064e52006-03-16 16:04:58 +01005303 return 0;
5304}
5305
5306
5307/*
Matt2f2f4252005-04-13 14:45:30 +02005308 * patch entries
5309 */
5310struct hda_codec_preset snd_hda_preset_sigmatel[] = {
5311 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
5312 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
5313 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
5314 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
5315 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
5316 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
5317 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02005318 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
5319 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
5320 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
5321 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
5322 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
5323 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01005324 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
5325 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
5326 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
5327 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
5328 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
5329 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
5330 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
5331 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
5332 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
5333 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01005334 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
5335 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
5336 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
5337 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
5338 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
5339 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02005340 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
5341 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02005342 /* The following does not take into account .id=0x83847661 when subsys =
5343 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
5344 * currently not fully supported.
5345 */
5346 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
5347 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
5348 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02005349 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
5350 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
5351 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
5352 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
5353 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
5354 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
5355 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
5356 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005357 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005358 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
5359 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005360 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01005361 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
5362 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005363 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01005364 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5365 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5366 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5367 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5368 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5369 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5370 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
5371 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02005372 {} /* terminator */
5373};