blob: c461baa83c2a9ead2c669bc86460215340bbe4aa [file] [log] [blame]
Matt2f2f4252005-04-13 14:45:30 +02001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for SigmaTel STAC92xx
5 *
6 * Copyright (c) 2005 Embedded Alley Solutions, Inc.
Matt Porter403d1942005-11-29 15:00:51 +01007 * Matt Porter <mporter@embeddedalley.com>
Matt2f2f4252005-04-13 14:45:30 +02008 *
9 * Based on patch_cmedia.c and patch_realtek.c
10 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
11 *
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
Matt2f2f4252005-04-13 14:45:30 +020027#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020032#include <sound/asoundef.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include "hda_codec.h"
34#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010035#include "hda_patch.h"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020036#include "hda_beep.h"
Matt2f2f4252005-04-13 14:45:30 +020037
Matt4e550962005-07-04 17:51:39 +020038#define NUM_CONTROL_ALLOC 32
Matthew Ranostaya64135a2008-01-10 16:55:06 +010039#define STAC_PWR_EVENT 0x20
40#define STAC_HP_EVENT 0x30
Matthew Ranostay72474be2008-10-09 09:32:17 -040041#define STAC_VREF_EVENT 0x40
Matt4e550962005-07-04 17:51:39 +020042
Takashi Iwaif5fcc132006-11-24 17:07:44 +010043enum {
44 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010045 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020046 STAC_9200_DELL_D21,
47 STAC_9200_DELL_D22,
48 STAC_9200_DELL_D23,
49 STAC_9200_DELL_M21,
50 STAC_9200_DELL_M22,
51 STAC_9200_DELL_M23,
52 STAC_9200_DELL_M24,
53 STAC_9200_DELL_M25,
54 STAC_9200_DELL_M26,
55 STAC_9200_DELL_M27,
Takashi Iwai1194b5b2007-10-10 10:04:26 +020056 STAC_9200_GATEWAY,
Takashi Iwai117f2572008-03-18 09:53:23 +010057 STAC_9200_PANASONIC,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010058 STAC_9200_MODELS
59};
60
61enum {
62 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020063 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020064 STAC_9205_DELL_M43,
65 STAC_9205_DELL_M44,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010066 STAC_9205_MODELS
67};
68
69enum {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010070 STAC_92HD73XX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010071 STAC_DELL_M6,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010072 STAC_92HD73XX_MODELS
73};
74
75enum {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020076 STAC_92HD83XXX_REF,
77 STAC_92HD83XXX_MODELS
78};
79
80enum {
Matthew Ranostaye035b842007-11-06 11:53:55 +010081 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +010082 STAC_DELL_M4_1,
83 STAC_DELL_M4_2,
Matthew Ranostay6a14f582008-09-12 12:02:30 -040084 STAC_HP_M4,
Matthew Ranostaye035b842007-11-06 11:53:55 +010085 STAC_92HD71BXX_MODELS
86};
87
88enum {
Tobin Davis8e21c342007-01-08 11:04:17 +010089 STAC_925x_REF,
90 STAC_M2_2,
91 STAC_MA6,
Tobin Davis2c11f952007-05-17 09:36:34 +020092 STAC_PA6,
Tobin Davis8e21c342007-01-08 11:04:17 +010093 STAC_925x_MODELS
94};
95
96enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010097 STAC_D945_REF,
98 STAC_D945GTP3,
99 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200100 STAC_INTEL_MAC_V1,
101 STAC_INTEL_MAC_V2,
102 STAC_INTEL_MAC_V3,
103 STAC_INTEL_MAC_V4,
104 STAC_INTEL_MAC_V5,
Nicolas Boichat536319a2008-07-21 22:18:01 +0800105 STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter
106 * is given, one of the above models will be
107 * chosen according to the subsystem id. */
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200108 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100109 STAC_MACMINI,
Takashi Iwai3fc24d82007-02-16 13:27:18 +0100110 STAC_MACBOOK,
Nicolas Boichat6f0778d2007-03-15 12:38:15 +0100111 STAC_MACBOOK_PRO_V1,
112 STAC_MACBOOK_PRO_V2,
Sylvain FORETf16928f2007-04-27 14:22:36 +0200113 STAC_IMAC_INTEL,
Takashi Iwai0dae0f82007-05-21 12:41:29 +0200114 STAC_IMAC_INTEL_20,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300115 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200116 STAC_922X_DELL_D81,
117 STAC_922X_DELL_D82,
118 STAC_922X_DELL_M81,
119 STAC_922X_DELL_M82,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100120 STAC_922X_MODELS
121};
122
123enum {
124 STAC_D965_REF,
125 STAC_D965_3ST,
126 STAC_D965_5ST,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200127 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100128 STAC_DELL_BIOS,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100129 STAC_927X_MODELS
130};
Matt Porter403d1942005-11-29 15:00:51 +0100131
Matt2f2f4252005-04-13 14:45:30 +0200132struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100133 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200134 unsigned int num_mixers;
135
Matt Porter403d1942005-11-29 15:00:51 +0100136 int board_config;
Mattc7d4b2f2005-06-27 14:59:41 +0200137 unsigned int surr_switch: 1;
Matt Porter403d1942005-11-29 15:00:51 +0100138 unsigned int line_switch: 1;
139 unsigned int mic_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100140 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100141 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400142 unsigned int spdif_mute: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200143
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +0100144 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200145 unsigned int eapd_mask;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +0100146 unsigned int gpio_mask;
147 unsigned int gpio_dir;
148 unsigned int gpio_data;
149 unsigned int gpio_mute;
150
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200151 /* stream */
152 unsigned int stream_delay;
153
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +0100154 /* analog loopback */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100155 unsigned char aloopback_mask;
156 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200157
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100158 /* power management */
159 unsigned int num_pwrs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200160 unsigned int *pwr_mapping;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100161 hda_nid_t *pwr_nids;
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100162 hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100163
Matt2f2f4252005-04-13 14:45:30 +0200164 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100165 struct hda_input_mux *mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400166 struct hda_input_mux *amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100167 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200168 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100169 hda_nid_t dac_nids[5];
Matt2f2f4252005-04-13 14:45:30 +0200170
171 /* capture */
172 hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200173 unsigned int num_adcs;
Mattdabbed62005-06-14 10:19:34 +0200174 hda_nid_t *mux_nids;
175 unsigned int num_muxes;
Matt Porter8b657272006-10-26 17:12:59 +0200176 hda_nid_t *dmic_nids;
177 unsigned int num_dmics;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100178 hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100179 unsigned int num_dmuxes;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200180 hda_nid_t *smux_nids;
181 unsigned int num_smuxes;
Matthew Ranostay65973632008-09-16 10:39:37 -0400182 const char **spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200183
Mattdabbed62005-06-14 10:19:34 +0200184 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100185 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200186 hda_nid_t anabeep_nid;
187 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200188
Matt2f2f4252005-04-13 14:45:30 +0200189 /* pin widgets */
190 hda_nid_t *pin_nids;
191 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200192 unsigned int *pin_configs;
Richard Fish11b44bb2006-08-23 18:31:34 +0200193 unsigned int *bios_pin_configs;
Matt2f2f4252005-04-13 14:45:30 +0200194
195 /* codec specific stuff */
196 struct hda_verb *init;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100197 struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200198
199 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200200 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100201 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200202 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100203 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200204 struct hda_input_mux *sinput_mux;
205 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400206 unsigned int cur_amux;
207 hda_nid_t *amp_nids;
208 unsigned int num_amps;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200209 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200210
Matt Porter403d1942005-11-29 15:00:51 +0100211 /* i/o switches */
212 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200213 unsigned int clfe_swap;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +0200214 unsigned int hp_switch;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200215 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200216
Mattc7d4b2f2005-06-27 14:59:41 +0200217 struct hda_pcm pcm_rec[2]; /* PCM information */
218
219 /* dynamic controls and input_mux */
220 struct auto_pin_cfg autocfg;
221 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100222 struct snd_kcontrol_new *kctl_alloc;
Matt Porter8b657272006-10-26 17:12:59 +0200223 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200224 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200225 struct hda_input_mux private_smux;
Matthew Ranostay89385032008-09-11 09:49:39 -0400226 struct hda_input_mux private_amp_mux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100227 struct hda_input_mux private_mono_mux;
Matt2f2f4252005-04-13 14:45:30 +0200228};
229
230static hda_nid_t stac9200_adc_nids[1] = {
231 0x03,
232};
233
234static hda_nid_t stac9200_mux_nids[1] = {
235 0x0c,
236};
237
238static hda_nid_t stac9200_dac_nids[1] = {
239 0x02,
240};
241
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100242static hda_nid_t stac92hd73xx_pwr_nids[8] = {
243 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
244 0x0f, 0x10, 0x11
245};
246
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400247static hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
248 0x26, 0,
249};
250
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100251static hda_nid_t stac92hd73xx_adc_nids[2] = {
252 0x1a, 0x1b
253};
254
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400255#define DELL_M6_AMP 2
256static hda_nid_t stac92hd73xx_amp_nids[3] = {
257 0x0b, 0x0c, 0x0e
Matthew Ranostay89385032008-09-11 09:49:39 -0400258};
259
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100260#define STAC92HD73XX_NUM_DMICS 2
261static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
262 0x13, 0x14, 0
263};
264
265#define STAC92HD73_DAC_COUNT 5
266static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
267 0x15, 0x16, 0x17, 0x18, 0x19,
268};
269
270static hda_nid_t stac92hd73xx_mux_nids[4] = {
271 0x28, 0x29, 0x2a, 0x2b,
272};
273
274static hda_nid_t stac92hd73xx_dmux_nids[2] = {
275 0x20, 0x21,
276};
277
Matthew Ranostayd9737752008-09-07 12:03:41 +0200278static hda_nid_t stac92hd73xx_smux_nids[2] = {
279 0x22, 0x23,
280};
281
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200282#define STAC92HD83XXX_NUM_DMICS 2
283static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
284 0x11, 0x12, 0
285};
286
287#define STAC92HD81_DAC_COUNT 2
288#define STAC92HD83_DAC_COUNT 3
289static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = {
290 0x13, 0x14, 0x22,
291};
292
293static hda_nid_t stac92hd83xxx_dmux_nids[2] = {
294 0x17, 0x18,
295};
296
297static hda_nid_t stac92hd83xxx_adc_nids[2] = {
298 0x15, 0x16,
299};
300
301static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
302 0xa, 0xb, 0xd, 0xe,
303};
304
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400305static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
306 0x1e, 0,
307};
308
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200309static unsigned int stac92hd83xxx_pwr_mapping[4] = {
310 0x03, 0x0c, 0x10, 0x40,
311};
312
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100313static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
314 0x0a, 0x0d, 0x0f
315};
316
Matthew Ranostaye035b842007-11-06 11:53:55 +0100317static hda_nid_t stac92hd71bxx_adc_nids[2] = {
318 0x12, 0x13,
319};
320
321static hda_nid_t stac92hd71bxx_mux_nids[2] = {
322 0x1a, 0x1b
323};
324
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100325static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
326 0x1c,
327};
328
Matthew Ranostayd9737752008-09-07 12:03:41 +0200329static hda_nid_t stac92hd71bxx_smux_nids[2] = {
330 0x24, 0x25,
331};
332
Takashi Iwaiaea7bb02008-02-25 18:26:41 +0100333static hda_nid_t stac92hd71bxx_dac_nids[1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100334 0x10, /*0x11, */
335};
336
337#define STAC92HD71BXX_NUM_DMICS 2
338static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
339 0x18, 0x19, 0
340};
341
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400342static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
343 0x22, 0
344};
345
Tobin Davis8e21c342007-01-08 11:04:17 +0100346static hda_nid_t stac925x_adc_nids[1] = {
347 0x03,
348};
349
350static hda_nid_t stac925x_mux_nids[1] = {
351 0x0f,
352};
353
354static hda_nid_t stac925x_dac_nids[1] = {
355 0x02,
356};
357
Takashi Iwaif6e98522007-10-16 14:27:04 +0200358#define STAC925X_NUM_DMICS 1
359static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
360 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200361};
362
Takashi Iwai1697055e2007-12-18 18:05:52 +0100363static hda_nid_t stac925x_dmux_nids[1] = {
364 0x14,
365};
366
Matt2f2f4252005-04-13 14:45:30 +0200367static hda_nid_t stac922x_adc_nids[2] = {
368 0x06, 0x07,
369};
370
371static hda_nid_t stac922x_mux_nids[2] = {
372 0x12, 0x13,
373};
374
Matt Porter3cc08dc2006-01-23 15:27:49 +0100375static hda_nid_t stac927x_adc_nids[3] = {
376 0x07, 0x08, 0x09
377};
378
379static hda_nid_t stac927x_mux_nids[3] = {
380 0x15, 0x16, 0x17
381};
382
Matthew Ranostayd9737752008-09-07 12:03:41 +0200383static hda_nid_t stac927x_smux_nids[1] = {
384 0x21,
385};
386
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100387static hda_nid_t stac927x_dac_nids[6] = {
388 0x02, 0x03, 0x04, 0x05, 0x06, 0
389};
390
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100391static hda_nid_t stac927x_dmux_nids[1] = {
392 0x1b,
393};
394
Matthew Ranostay7f168592007-10-18 17:38:17 +0200395#define STAC927X_NUM_DMICS 2
396static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
397 0x13, 0x14, 0
398};
399
Matthew Ranostay65973632008-09-16 10:39:37 -0400400static const char *stac927x_spdif_labels[5] = {
401 "Digital Playback", "ADAT", "Analog Mux 1",
402 "Analog Mux 2", "Analog Mux 3"
403};
404
Matt Porterf3302a52006-07-31 12:49:34 +0200405static hda_nid_t stac9205_adc_nids[2] = {
406 0x12, 0x13
407};
408
409static hda_nid_t stac9205_mux_nids[2] = {
410 0x19, 0x1a
411};
412
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100413static hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100414 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100415};
416
Matthew Ranostayd9737752008-09-07 12:03:41 +0200417static hda_nid_t stac9205_smux_nids[1] = {
418 0x21,
419};
420
Takashi Iwaif6e98522007-10-16 14:27:04 +0200421#define STAC9205_NUM_DMICS 2
422static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
423 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200424};
425
Mattc7d4b2f2005-06-27 14:59:41 +0200426static hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200427 0x08, 0x09, 0x0d, 0x0e,
428 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200429};
430
Tobin Davis8e21c342007-01-08 11:04:17 +0100431static hda_nid_t stac925x_pin_nids[8] = {
432 0x07, 0x08, 0x0a, 0x0b,
433 0x0c, 0x0d, 0x10, 0x11,
434};
435
Matt2f2f4252005-04-13 14:45:30 +0200436static hda_nid_t stac922x_pin_nids[10] = {
437 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
438 0x0f, 0x10, 0x11, 0x15, 0x1b,
439};
440
Matthew Ranostaya7662642008-02-21 07:51:14 +0100441static hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100442 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
443 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200444 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100445};
446
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200447static hda_nid_t stac92hd83xxx_pin_nids[14] = {
448 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
449 0x0f, 0x10, 0x11, 0x12, 0x13,
450 0x1d, 0x1e, 0x1f, 0x20
451};
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400452static hda_nid_t stac92hd71bxx_pin_nids[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100453 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
454 0x0f, 0x14, 0x18, 0x19, 0x1e,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400455 0x1f,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100456};
457
Matt Porter3cc08dc2006-01-23 15:27:49 +0100458static hda_nid_t stac927x_pin_nids[14] = {
459 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
460 0x0f, 0x10, 0x11, 0x12, 0x13,
461 0x14, 0x21, 0x22, 0x23,
462};
463
Matt Porterf3302a52006-07-31 12:49:34 +0200464static hda_nid_t stac9205_pin_nids[12] = {
465 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
466 0x0f, 0x14, 0x16, 0x17, 0x18,
467 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200468};
469
Matthew Ranostay89385032008-09-11 09:49:39 -0400470#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info
471
472static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_value *ucontrol)
474{
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 struct sigmatel_spec *spec = codec->spec;
477 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
478
479 kcontrol->private_value ^= get_amp_nid(kcontrol);
480 kcontrol->private_value |= nid;
481
482 return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
483}
484
485static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol,
486 struct snd_ctl_elem_value *ucontrol)
487{
488 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
489 struct sigmatel_spec *spec = codec->spec;
490 hda_nid_t nid = spec->amp_nids[spec->cur_amux];
491
492 kcontrol->private_value ^= get_amp_nid(kcontrol);
493 kcontrol->private_value |= nid;
494
495 return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
496}
497
Matt Porter8b657272006-10-26 17:12:59 +0200498static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_info *uinfo)
500{
501 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
502 struct sigmatel_spec *spec = codec->spec;
503 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
504}
505
506static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
507 struct snd_ctl_elem_value *ucontrol)
508{
509 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
510 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100511 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200512
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100513 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200514 return 0;
515}
516
517static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
518 struct snd_ctl_elem_value *ucontrol)
519{
520 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
521 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100522 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200523
524 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100525 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200526}
527
Matthew Ranostayd9737752008-09-07 12:03:41 +0200528static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
529 struct snd_ctl_elem_info *uinfo)
530{
531 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
532 struct sigmatel_spec *spec = codec->spec;
533 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
534}
535
536static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_value *ucontrol)
538{
539 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
540 struct sigmatel_spec *spec = codec->spec;
541 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
542
543 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
544 return 0;
545}
546
547static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
548 struct snd_ctl_elem_value *ucontrol)
549{
550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
551 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400552 struct hda_input_mux *smux = &spec->private_smux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200553 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400554 int err, val;
555 hda_nid_t nid;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200556
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400557 err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200558 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400559 if (err < 0)
560 return err;
561
562 if (spec->spdif_mute) {
563 if (smux_idx == 0)
564 nid = spec->multiout.dig_out_nid;
565 else
566 nid = codec->slave_dig_outs[smux_idx - 1];
567 if (spec->cur_smux[smux_idx] == smux->num_items - 1)
568 val = AMP_OUT_MUTE;
569 if (smux_idx == 0)
570 nid = spec->multiout.dig_out_nid;
571 else
572 nid = codec->slave_dig_outs[smux_idx - 1];
573 /* un/mute SPDIF out */
574 snd_hda_codec_write_cache(codec, nid, 0,
575 AC_VERB_SET_AMP_GAIN_MUTE, val);
576 }
577 return 0;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200578}
579
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100580static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200581{
582 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
583 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200584 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200585}
586
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100587static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200588{
589 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
590 struct sigmatel_spec *spec = codec->spec;
591 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
592
593 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
594 return 0;
595}
596
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100597static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200598{
599 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
600 struct sigmatel_spec *spec = codec->spec;
601 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
602
Mattc7d4b2f2005-06-27 14:59:41 +0200603 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Matt2f2f4252005-04-13 14:45:30 +0200604 spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
605}
606
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100607static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
608 struct snd_ctl_elem_info *uinfo)
609{
610 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
611 struct sigmatel_spec *spec = codec->spec;
612 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
613}
614
615static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
616 struct snd_ctl_elem_value *ucontrol)
617{
618 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
619 struct sigmatel_spec *spec = codec->spec;
620
621 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
622 return 0;
623}
624
625static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
626 struct snd_ctl_elem_value *ucontrol)
627{
628 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
629 struct sigmatel_spec *spec = codec->spec;
630
631 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
632 spec->mono_nid, &spec->cur_mmux);
633}
634
Matthew Ranostay89385032008-09-11 09:49:39 -0400635static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol,
636 struct snd_ctl_elem_info *uinfo)
637{
638 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
639 struct sigmatel_spec *spec = codec->spec;
640 return snd_hda_input_mux_info(spec->amp_mux, uinfo);
641}
642
643static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol,
644 struct snd_ctl_elem_value *ucontrol)
645{
646 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
647 struct sigmatel_spec *spec = codec->spec;
648
649 ucontrol->value.enumerated.item[0] = spec->cur_amux;
650 return 0;
651}
652
653static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol,
654 struct snd_ctl_elem_value *ucontrol)
655{
656 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
657 struct sigmatel_spec *spec = codec->spec;
658 struct snd_kcontrol *ctl =
659 snd_hda_find_mixer_ctl(codec, "Amp Capture Volume");
660 if (!ctl)
661 return -EINVAL;
662
663 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE |
664 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
665
666 return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol,
667 0, &spec->cur_amux);
668}
669
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200670#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
671
672static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
673 struct snd_ctl_elem_value *ucontrol)
674{
675 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100676 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200677 struct sigmatel_spec *spec = codec->spec;
678
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100679 ucontrol->value.integer.value[0] = !!(spec->aloopback &
680 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200681 return 0;
682}
683
684static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
685 struct snd_ctl_elem_value *ucontrol)
686{
687 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
688 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100689 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200690 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100691 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200692
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100693 idx_val = spec->aloopback_mask << idx;
694 if (ucontrol->value.integer.value[0])
695 val = spec->aloopback | idx_val;
696 else
697 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100698 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200699 return 0;
700
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100701 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200702
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100703 /* Only return the bits defined by the shift value of the
704 * first two bytes of the mask
705 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200706 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100707 kcontrol->private_value & 0xFFFF, 0x0);
708 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200709
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100710 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200711 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100712 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200713 } else {
714 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100715 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200716 }
717
718 snd_hda_codec_write_cache(codec, codec->afg, 0,
719 kcontrol->private_value >> 16, dac_mode);
720
721 return 1;
722}
723
Mattc7d4b2f2005-06-27 14:59:41 +0200724static struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200725 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200726 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200727 {}
728};
729
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200730static struct hda_verb stac9200_eapd_init[] = {
731 /* set dac0mux for dac converter */
732 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
733 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
734 {}
735};
736
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100737static struct hda_verb stac92hd73xx_6ch_core_init[] = {
738 /* set master volume and direct control */
739 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
740 /* setup audio connections */
741 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
742 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
743 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
744 /* setup adcs to point to mixer */
745 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
746 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100747 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
748 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
749 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
750 /* setup import muxs */
751 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
752 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
753 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
754 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
755 {}
756};
757
Matthew Ranostayd654a662008-03-14 08:46:51 +0100758static struct hda_verb dell_eq_core_init[] = {
759 /* set master volume to max value without distortion
760 * and direct control */
761 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
762 /* setup audio connections */
763 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
Matthew Ranostayf7cf0a72008-09-13 10:36:58 -0400764 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02},
765 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayd654a662008-03-14 08:46:51 +0100766 /* setup adcs to point to mixer */
767 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
768 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
769 /* setup import muxs */
770 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
771 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
772 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
773 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
774 {}
775};
776
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100777static struct hda_verb dell_m6_core_init[] = {
Matthew Ranostay20f5f952008-09-01 08:17:56 +0200778 /* set master volume to max value without distortion
779 * and direct control */
780 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100781 /* setup audio connections */
Matthew Ranostay7747ecc2008-03-10 11:30:04 +0100782 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
783 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay52fe0f92008-02-29 12:08:20 +0100784 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
785 /* setup adcs to point to mixer */
786 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
787 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
788 /* setup import muxs */
789 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
790 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
791 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
792 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
793 {}
794};
795
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100796static struct hda_verb stac92hd73xx_8ch_core_init[] = {
797 /* set master volume and direct control */
798 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
799 /* setup audio connections */
800 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
801 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
802 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
803 /* connect hp ports to dac3 */
804 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
805 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
806 /* setup adcs to point to mixer */
807 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
808 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100809 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
810 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
811 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
812 /* setup import muxs */
813 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
814 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
815 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
816 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
817 {}
818};
819
820static struct hda_verb stac92hd73xx_10ch_core_init[] = {
821 /* set master volume and direct control */
822 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
823 /* setup audio connections */
824 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
825 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
826 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
827 /* dac3 is connected to import3 mux */
828 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
829 /* connect hp ports to dac4 */
830 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
831 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
832 /* setup adcs to point to mixer */
833 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
834 { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100835 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
836 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
837 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
838 /* setup import muxs */
839 { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
840 { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
841 { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
842 { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
843 {}
844};
845
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200846static struct hda_verb stac92hd83xxx_core_init[] = {
847 /* start of config #1 */
848 { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3},
849
850 /* start of config #2 */
851 { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0},
852 { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0},
853 { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1},
854
855 /* power state controls amps */
856 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
857};
858
Matthew Ranostaye035b842007-11-06 11:53:55 +0100859static struct hda_verb stac92hd71bxx_core_init[] = {
860 /* set master volume and direct control */
861 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
862 /* connect headphone jack to dac1 */
863 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100864 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
865 /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
866 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
867 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
868 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostay541eee82007-12-14 12:08:04 +0100869};
870
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200871#define HD_DISABLE_PORTF 3
Matthew Ranostay541eee82007-12-14 12:08:04 +0100872static struct hda_verb stac92hd71bxx_analog_core_init[] = {
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200873 /* start of config #1 */
874
875 /* connect port 0f to audio mixer */
876 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
877 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
878 /* unmute right and left channels for node 0x0f */
879 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
880 /* start of config #2 */
881
Matthew Ranostay541eee82007-12-14 12:08:04 +0100882 /* set master volume and direct control */
883 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
884 /* connect headphone jack to dac1 */
885 { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200886 /* connect port 0d to audio mixer */
Matthew Ranostay9b359472007-11-07 13:03:12 +0100887 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
Matthew Ranostay9b359472007-11-07 13:03:12 +0100888 /* unmute dac0 input in audio mixer */
889 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
Matthew Ranostayaafc4412008-06-13 18:04:33 +0200890 /* unmute right and left channels for nodes 0x0a, 0xd */
Matthew Ranostaye035b842007-11-06 11:53:55 +0100891 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
892 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100893 {}
894};
895
Tobin Davis8e21c342007-01-08 11:04:17 +0100896static struct hda_verb stac925x_core_init[] = {
897 /* set dac0mux for dac converter */
898 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
899 {}
900};
901
Mattc7d4b2f2005-06-27 14:59:41 +0200902static struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200903 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200904 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200905 {}
906};
907
Tobin Davis93ed1502006-09-01 21:03:12 +0200908static struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200909 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200910 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200911 /* unmute node 0x1b */
912 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
913 /* select node 0x03 as DAC */
914 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
915 {}
916};
917
Matt Porter3cc08dc2006-01-23 15:27:49 +0100918static struct hda_verb stac927x_core_init[] = {
919 /* set master volume and direct control */
920 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200921 /* enable analog pc beep path */
922 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100923 {}
924};
925
Matt Porterf3302a52006-07-31 12:49:34 +0200926static struct hda_verb stac9205_core_init[] = {
927 /* set master volume and direct control */
928 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200929 /* enable analog pc beep path */
930 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200931 {}
932};
933
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100934#define STAC_MONO_MUX \
935 { \
936 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
937 .name = "Mono Mux", \
938 .count = 1, \
939 .info = stac92xx_mono_mux_enum_info, \
940 .get = stac92xx_mono_mux_enum_get, \
941 .put = stac92xx_mono_mux_enum_put, \
942 }
943
Matthew Ranostay89385032008-09-11 09:49:39 -0400944#define STAC_AMP_MUX \
945 { \
946 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
947 .name = "Amp Selector Capture Switch", \
948 .count = 1, \
949 .info = stac92xx_amp_mux_enum_info, \
950 .get = stac92xx_amp_mux_enum_get, \
951 .put = stac92xx_amp_mux_enum_put, \
952 }
953
954#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \
955 { \
956 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
957 .name = xname, \
958 .index = 0, \
959 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
960 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
961 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
962 .info = stac92xx_amp_volume_info, \
963 .get = stac92xx_amp_volume_get, \
964 .put = stac92xx_amp_volume_put, \
965 .tlv = { .c = snd_hda_mixer_amp_tlv }, \
966 .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \
967 }
968
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200969#define STAC_INPUT_SOURCE(cnt) \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200970 { \
971 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
972 .name = "Input Source", \
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200973 .count = cnt, \
Maxim Levitskyca7c5a82007-08-31 12:52:19 +0200974 .info = stac92xx_mux_enum_info, \
975 .get = stac92xx_mux_enum_get, \
976 .put = stac92xx_mux_enum_put, \
977 }
978
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100979#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200980 { \
981 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
982 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100983 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200984 .info = stac92xx_aloopback_info, \
985 .get = stac92xx_aloopback_get, \
986 .put = stac92xx_aloopback_put, \
987 .private_value = verb_read | (verb_write << 16), \
988 }
989
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100990static struct snd_kcontrol_new stac9200_mixer[] = {
Matt2f2f4252005-04-13 14:45:30 +0200991 HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
992 HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +0200993 STAC_INPUT_SOURCE(1),
Matt2f2f4252005-04-13 14:45:30 +0200994 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
995 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +0200996 { } /* end */
997};
998
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400999#define DELL_M6_MIXER 6
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001000static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04001001 /* start of config #1 */
1002 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1003 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1004
1005 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1006 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1007
1008 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1009 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1010
1011 /* start of config #2 */
1012 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1013 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1014
1015 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1016 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1017
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001018 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
1019
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001020 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1021 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1022
1023 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1024 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1025
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001026 { } /* end */
1027};
1028
1029static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001030 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1031
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001032 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1033 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1034
1035 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1036 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1037
1038 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1039 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1040
1041 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1042 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1043
1044 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1045 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1046
1047 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1048 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1049
1050 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1051 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1052 { } /* end */
1053};
1054
1055static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001056 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1057
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001058 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
1059 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
1060
1061 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
1062 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
1063
1064 HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
1065 HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
1066
1067 HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
1068 HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
1069
1070 HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
1071 HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
1072
1073 HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
1074 HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
1075
1076 HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
1077 HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
1078 { } /* end */
1079};
1080
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001081
1082static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
1083 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT),
1084 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT),
1085
1086 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT),
1087 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT),
1088
1089 HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT),
1090 HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT),
1091
1092 HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT),
1093 HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT),
1094
1095 HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT),
1096 HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT),
1097
1098 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT),
1099 HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT),
1100
1101 /*
1102 HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT),
1103 HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT),
1104 */
1105 { } /* end */
1106};
1107
Matthew Ranostay541eee82007-12-14 12:08:04 +01001108static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001109 STAC_INPUT_SOURCE(2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001110
Matthew Ranostay9b359472007-11-07 13:03:12 +01001111 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1112 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay9b359472007-11-07 13:03:12 +01001113
1114 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1115 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001116 /* analog pc-beep replaced with digital beep support */
1117 /*
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001118 HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
1119 HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
Matthew Ranostay1cd22242008-07-18 18:20:52 +02001120 */
Matthew Ranostayf7c5dda2008-07-10 17:49:11 +02001121
Matthew Ranostay9b359472007-11-07 13:03:12 +01001122 HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
1123 HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001124 { } /* end */
1125};
1126
Matthew Ranostay541eee82007-12-14 12:08:04 +01001127static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
Matthew Ranostay541eee82007-12-14 12:08:04 +01001128 STAC_INPUT_SOURCE(2),
1129 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
1130
Matthew Ranostay541eee82007-12-14 12:08:04 +01001131 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
1132 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001133
1134 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
1135 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
Matthew Ranostay541eee82007-12-14 12:08:04 +01001136 { } /* end */
1137};
1138
Tobin Davis8e21c342007-01-08 11:04:17 +01001139static struct snd_kcontrol_new stac925x_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001140 STAC_INPUT_SOURCE(1),
Tobin Davis8e21c342007-01-08 11:04:17 +01001141 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
Mauro Carvalho Chehab587755f2008-05-25 18:20:06 +02001142 HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT),
Tobin Davis8e21c342007-01-08 11:04:17 +01001143 { } /* end */
1144};
1145
Takashi Iwaid1d985f2006-11-23 19:27:12 +01001146static struct snd_kcontrol_new stac9205_mixer[] = {
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001147 STAC_INPUT_SOURCE(2),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001148 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001149
1150 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
1151 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001152
1153 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT),
1154 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001155 { } /* end */
1156};
1157
1158/* This needs to be generated dynamically based on sequence */
1159static struct snd_kcontrol_new stac922x_mixer[] = {
1160 STAC_INPUT_SOURCE(2),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001161 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT),
1162 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001163
1164 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT),
1165 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001166 { } /* end */
1167};
1168
1169
1170static struct snd_kcontrol_new stac927x_mixer[] = {
1171 STAC_INPUT_SOURCE(3),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001172 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001173
1174 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
1175 HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001176
1177 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT),
1178 HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001179
1180 HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT),
1181 HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT),
Matt Porterf3302a52006-07-31 12:49:34 +02001182 { } /* end */
1183};
1184
Takashi Iwai1697055e2007-12-18 18:05:52 +01001185static struct snd_kcontrol_new stac_dmux_mixer = {
1186 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1187 .name = "Digital Input Source",
1188 /* count set later */
1189 .info = stac92xx_dmux_enum_info,
1190 .get = stac92xx_dmux_enum_get,
1191 .put = stac92xx_dmux_enum_put,
1192};
1193
Matthew Ranostayd9737752008-09-07 12:03:41 +02001194static struct snd_kcontrol_new stac_smux_mixer = {
1195 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001196 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001197 /* count set later */
1198 .info = stac92xx_smux_enum_info,
1199 .get = stac92xx_smux_enum_get,
1200 .put = stac92xx_smux_enum_put,
1201};
1202
Takashi Iwai2134ea42008-01-10 16:53:55 +01001203static const char *slave_vols[] = {
1204 "Front Playback Volume",
1205 "Surround Playback Volume",
1206 "Center Playback Volume",
1207 "LFE Playback Volume",
1208 "Side Playback Volume",
1209 "Headphone Playback Volume",
1210 "Headphone Playback Volume",
1211 "Speaker Playback Volume",
1212 "External Speaker Playback Volume",
1213 "Speaker2 Playback Volume",
1214 NULL
1215};
1216
1217static const char *slave_sws[] = {
1218 "Front Playback Switch",
1219 "Surround Playback Switch",
1220 "Center Playback Switch",
1221 "LFE Playback Switch",
1222 "Side Playback Switch",
1223 "Headphone Playback Switch",
1224 "Headphone Playback Switch",
1225 "Speaker Playback Switch",
1226 "External Speaker Playback Switch",
1227 "Speaker2 Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001228 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001229 NULL
1230};
1231
Matt2f2f4252005-04-13 14:45:30 +02001232static int stac92xx_build_controls(struct hda_codec *codec)
1233{
1234 struct sigmatel_spec *spec = codec->spec;
1235 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001236 int i;
Matt2f2f4252005-04-13 14:45:30 +02001237
1238 err = snd_hda_add_new_ctls(codec, spec->mixer);
1239 if (err < 0)
1240 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02001241
1242 for (i = 0; i < spec->num_mixers; i++) {
1243 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1244 if (err < 0)
1245 return err;
1246 }
Takashi Iwai1697055e2007-12-18 18:05:52 +01001247 if (spec->num_dmuxes > 0) {
1248 stac_dmux_mixer.count = spec->num_dmuxes;
1249 err = snd_ctl_add(codec->bus->card,
1250 snd_ctl_new1(&stac_dmux_mixer, codec));
1251 if (err < 0)
1252 return err;
1253 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001254 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001255 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1256 struct hda_input_mux *smux = &spec->private_smux;
1257 /* check for mute support on SPDIF out */
1258 if (wcaps & AC_WCAP_OUT_AMP) {
1259 smux->items[smux->num_items].label = "Off";
1260 smux->items[smux->num_items].index = 0;
1261 smux->num_items++;
1262 spec->spdif_mute = 1;
1263 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001264 stac_smux_mixer.count = spec->num_smuxes;
1265 err = snd_ctl_add(codec->bus->card,
1266 snd_ctl_new1(&stac_smux_mixer, codec));
1267 if (err < 0)
1268 return err;
1269 }
Mattc7d4b2f2005-06-27 14:59:41 +02001270
Mattdabbed62005-06-14 10:19:34 +02001271 if (spec->multiout.dig_out_nid) {
1272 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
1273 if (err < 0)
1274 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001275 err = snd_hda_create_spdif_share_sw(codec,
1276 &spec->multiout);
1277 if (err < 0)
1278 return err;
1279 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001280 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04001281 if (spec->dig_in_nid && (!spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001282 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1283 if (err < 0)
1284 return err;
1285 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001286
1287 /* if we have no master control, let's create it */
1288 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001289 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001290 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001291 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001292 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001293 vmaster_tlv, slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001294 if (err < 0)
1295 return err;
1296 }
1297 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1298 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1299 NULL, slave_sws);
1300 if (err < 0)
1301 return err;
1302 }
1303
Mattdabbed62005-06-14 10:19:34 +02001304 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001305}
1306
Matt Porter403d1942005-11-29 15:00:51 +01001307static unsigned int ref9200_pin_configs[8] = {
Mattdabbed62005-06-14 10:19:34 +02001308 0x01c47010, 0x01447010, 0x0221401f, 0x01114010,
Matt2f2f4252005-04-13 14:45:30 +02001309 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
1310};
1311
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001312/*
1313 STAC 9200 pin configs for
1314 102801A8
1315 102801DE
1316 102801E8
1317*/
1318static unsigned int dell9200_d21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001319 0x400001f0, 0x400001f1, 0x02214030, 0x01014010,
1320 0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001321};
1322
1323/*
1324 STAC 9200 pin configs for
1325 102801C0
1326 102801C1
1327*/
1328static unsigned int dell9200_d22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001329 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1330 0x01813020, 0x02a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001331};
1332
1333/*
1334 STAC 9200 pin configs for
1335 102801C4 (Dell Dimension E310)
1336 102801C5
1337 102801C7
1338 102801D9
1339 102801DA
1340 102801E3
1341*/
1342static unsigned int dell9200_d23_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001343 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010,
1344 0x01813020, 0x01a19021, 0x90100140, 0x400001f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001345};
1346
1347
1348/*
1349 STAC 9200-32 pin configs for
1350 102801B5 (Dell Inspiron 630m)
1351 102801D8 (Dell Inspiron 640m)
1352*/
1353static unsigned int dell9200_m21_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001354 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310,
1355 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001356};
1357
1358/*
1359 STAC 9200-32 pin configs for
1360 102801C2 (Dell Latitude D620)
1361 102801C8
1362 102801CC (Dell Latitude D820)
1363 102801D4
1364 102801D6
1365*/
1366static unsigned int dell9200_m22_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001367 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310,
1368 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001369};
1370
1371/*
1372 STAC 9200-32 pin configs for
1373 102801CE (Dell XPS M1710)
1374 102801CF (Dell Precision M90)
1375*/
1376static unsigned int dell9200_m23_pin_configs[8] = {
1377 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310,
1378 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc,
1379};
1380
1381/*
1382 STAC 9200-32 pin configs for
1383 102801C9
1384 102801CA
1385 102801CB (Dell Latitude 120L)
1386 102801D3
1387*/
1388static unsigned int dell9200_m24_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001389 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310,
1390 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001391};
1392
1393/*
1394 STAC 9200-32 pin configs for
1395 102801BD (Dell Inspiron E1505n)
1396 102801EE
1397 102801EF
1398*/
1399static unsigned int dell9200_m25_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001400 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1401 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001402};
1403
1404/*
1405 STAC 9200-32 pin configs for
1406 102801F5 (Dell Inspiron 1501)
1407 102801F6
1408*/
1409static unsigned int dell9200_m26_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001410 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310,
1411 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001412};
1413
1414/*
1415 STAC 9200-32
1416 102801CD (Dell Inspiron E1705/9400)
1417*/
1418static unsigned int dell9200_m27_pin_configs[8] = {
Takashi Iwaiaf6c0162007-09-05 23:46:03 +02001419 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310,
1420 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001421};
1422
Tobin Davisbf277782008-02-03 20:31:47 +01001423static unsigned int oqo9200_pin_configs[8] = {
1424 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
1425 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
1426};
1427
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001428
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001429static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
1430 [STAC_REF] = ref9200_pin_configs,
Tobin Davisbf277782008-02-03 20:31:47 +01001431 [STAC_9200_OQO] = oqo9200_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001432 [STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
1433 [STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
1434 [STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
1435 [STAC_9200_DELL_M21] = dell9200_m21_pin_configs,
1436 [STAC_9200_DELL_M22] = dell9200_m22_pin_configs,
1437 [STAC_9200_DELL_M23] = dell9200_m23_pin_configs,
1438 [STAC_9200_DELL_M24] = dell9200_m24_pin_configs,
1439 [STAC_9200_DELL_M25] = dell9200_m25_pin_configs,
1440 [STAC_9200_DELL_M26] = dell9200_m26_pin_configs,
1441 [STAC_9200_DELL_M27] = dell9200_m27_pin_configs,
Takashi Iwai117f2572008-03-18 09:53:23 +01001442 [STAC_9200_PANASONIC] = ref9200_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001443};
1444
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001445static const char *stac9200_models[STAC_9200_MODELS] = {
1446 [STAC_REF] = "ref",
Tobin Davisbf277782008-02-03 20:31:47 +01001447 [STAC_9200_OQO] = "oqo",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001448 [STAC_9200_DELL_D21] = "dell-d21",
1449 [STAC_9200_DELL_D22] = "dell-d22",
1450 [STAC_9200_DELL_D23] = "dell-d23",
1451 [STAC_9200_DELL_M21] = "dell-m21",
1452 [STAC_9200_DELL_M22] = "dell-m22",
1453 [STAC_9200_DELL_M23] = "dell-m23",
1454 [STAC_9200_DELL_M24] = "dell-m24",
1455 [STAC_9200_DELL_M25] = "dell-m25",
1456 [STAC_9200_DELL_M26] = "dell-m26",
1457 [STAC_9200_DELL_M27] = "dell-m27",
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001458 [STAC_9200_GATEWAY] = "gateway",
Takashi Iwai117f2572008-03-18 09:53:23 +01001459 [STAC_9200_PANASONIC] = "panasonic",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001460};
1461
1462static struct snd_pci_quirk stac9200_cfg_tbl[] = {
1463 /* SigmaTel reference board */
1464 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1465 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001466 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001467 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1468 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001469 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001470 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1471 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1472 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1473 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1474 "unknown Dell", STAC_9200_DELL_D22),
1475 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1476 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001477 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001478 "Dell Latitude D620", STAC_9200_DELL_M22),
1479 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1480 "unknown Dell", STAC_9200_DELL_D23),
1481 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1482 "unknown Dell", STAC_9200_DELL_D23),
1483 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1484 "unknown Dell", STAC_9200_DELL_M22),
1485 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1486 "unknown Dell", STAC_9200_DELL_M24),
1487 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1488 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001489 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001490 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001491 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001492 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001493 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001494 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001495 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001496 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001497 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001498 "Dell Precision M90", STAC_9200_DELL_M23),
1499 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1500 "unknown Dell", STAC_9200_DELL_M22),
1501 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1502 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001503 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001504 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001505 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001506 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1507 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1508 "unknown Dell", STAC_9200_DELL_D23),
1509 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1510 "unknown Dell", STAC_9200_DELL_D23),
1511 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1512 "unknown Dell", STAC_9200_DELL_D21),
1513 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1514 "unknown Dell", STAC_9200_DELL_D23),
1515 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1516 "unknown Dell", STAC_9200_DELL_D21),
1517 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1518 "unknown Dell", STAC_9200_DELL_M25),
1519 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1520 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001521 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001522 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1523 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1524 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001525 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001526 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001527 /* Gateway machines needs EAPD to be set on resume */
1528 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY),
1529 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*",
1530 STAC_9200_GATEWAY),
1531 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
1532 STAC_9200_GATEWAY),
Tobin Davisbf277782008-02-03 20:31:47 +01001533 /* OQO Mobile */
1534 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001535 {} /* terminator */
1536};
1537
Tobin Davis8e21c342007-01-08 11:04:17 +01001538static unsigned int ref925x_pin_configs[8] = {
1539 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
Matthew Ranostay09a99952008-01-24 11:49:21 +01001540 0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001541};
1542
1543static unsigned int stac925x_MA6_pin_configs[8] = {
1544 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1545 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e,
1546};
1547
Tobin Davis2c11f952007-05-17 09:36:34 +02001548static unsigned int stac925x_PA6_pin_configs[8] = {
1549 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
1550 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e,
1551};
1552
Tobin Davis8e21c342007-01-08 11:04:17 +01001553static unsigned int stac925xM2_2_pin_configs[8] = {
Steve Longerbeam7353e142007-05-29 14:36:17 +02001554 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020,
1555 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e,
Tobin Davis8e21c342007-01-08 11:04:17 +01001556};
1557
1558static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
1559 [STAC_REF] = ref925x_pin_configs,
1560 [STAC_M2_2] = stac925xM2_2_pin_configs,
1561 [STAC_MA6] = stac925x_MA6_pin_configs,
Tobin Davis2c11f952007-05-17 09:36:34 +02001562 [STAC_PA6] = stac925x_PA6_pin_configs,
Tobin Davis8e21c342007-01-08 11:04:17 +01001563};
1564
1565static const char *stac925x_models[STAC_925x_MODELS] = {
1566 [STAC_REF] = "ref",
1567 [STAC_M2_2] = "m2-2",
1568 [STAC_MA6] = "m6",
Tobin Davis2c11f952007-05-17 09:36:34 +02001569 [STAC_PA6] = "pa6",
Tobin Davis8e21c342007-01-08 11:04:17 +01001570};
1571
1572static struct snd_pci_quirk stac925x_cfg_tbl[] = {
1573 /* SigmaTel reference board */
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
Tobin Davis2c11f952007-05-17 09:36:34 +02001575 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
Tobin Davis8e21c342007-01-08 11:04:17 +01001576 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF),
1577 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF),
1578 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6),
Tobin Davis2c11f952007-05-17 09:36:34 +02001579 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6),
Tobin Davis8e21c342007-01-08 11:04:17 +01001580 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2),
1581 {} /* terminator */
1582};
1583
Matthew Ranostaya7662642008-02-21 07:51:14 +01001584static unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001585 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1586 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1587 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001588 0x01452050,
1589};
1590
1591static unsigned int dell_m6_pin_configs[13] = {
1592 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001593 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001594 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1595 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001596};
1597
1598static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001599 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
1600 [STAC_DELL_M6] = dell_m6_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001601};
1602
1603static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
1604 [STAC_92HD73XX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001605 [STAC_DELL_M6] = "dell-m6",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001606};
1607
1608static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
1609 /* SigmaTel reference board */
1610 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001611 "DFI LanParty", STAC_92HD73XX_REF),
1612 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
1613 "unknown Dell", STAC_DELL_M6),
1614 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
1615 "unknown Dell", STAC_DELL_M6),
1616 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
1617 "unknown Dell", STAC_DELL_M6),
1618 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
1619 "unknown Dell", STAC_DELL_M6),
1620 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
1621 "unknown Dell", STAC_DELL_M6),
1622 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
1623 "unknown Dell", STAC_DELL_M6),
1624 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
1625 "unknown Dell", STAC_DELL_M6),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001626 {} /* terminator */
1627};
1628
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001629static unsigned int ref92hd83xxx_pin_configs[14] = {
1630 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1631 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
1632 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0,
1633 0x01451160, 0x98560170,
1634};
1635
1636static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
1637 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
1638};
1639
1640static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
1641 [STAC_92HD83XXX_REF] = "ref",
1642};
1643
1644static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
1645 /* SigmaTel reference board */
1646 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1647 "DFI LanParty", STAC_92HD71BXX_REF),
1648};
1649
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001650static unsigned int ref92hd71bxx_pin_configs[11] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01001651 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostayb22b4822008-01-22 12:32:30 +01001652 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001653 0x90a000f0, 0x01452050, 0x01452050,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001654};
1655
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001656static unsigned int dell_m4_1_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001657 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01001658 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001659 0x40f000f0, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001660};
1661
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001662static unsigned int dell_m4_2_pin_configs[11] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001663 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
1664 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04001665 0x40f000f0, 0x044413b0, 0x044413b0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001666};
1667
Matthew Ranostaye035b842007-11-06 11:53:55 +01001668static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
1669 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001670 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
1671 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001672 [STAC_HP_M4] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01001673};
1674
1675static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
1676 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01001677 [STAC_DELL_M4_1] = "dell-m4-1",
1678 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04001679 [STAC_HP_M4] = "hp-m4",
Matthew Ranostaye035b842007-11-06 11:53:55 +01001680};
1681
1682static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
1683 /* SigmaTel reference board */
1684 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1685 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04001686 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
1687 "unknown HP", STAC_HP_M4),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001688 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
1689 "unknown Dell", STAC_DELL_M4_1),
1690 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
1691 "unknown Dell", STAC_DELL_M4_1),
1692 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
1693 "unknown Dell", STAC_DELL_M4_1),
1694 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
1695 "unknown Dell", STAC_DELL_M4_1),
1696 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
1697 "unknown Dell", STAC_DELL_M4_1),
1698 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
1699 "unknown Dell", STAC_DELL_M4_1),
1700 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
1701 "unknown Dell", STAC_DELL_M4_1),
1702 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
1703 "unknown Dell", STAC_DELL_M4_2),
1704 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
1705 "unknown Dell", STAC_DELL_M4_2),
1706 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
1707 "unknown Dell", STAC_DELL_M4_2),
1708 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
1709 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostaye035b842007-11-06 11:53:55 +01001710 {} /* terminator */
1711};
1712
Matt Porter403d1942005-11-29 15:00:51 +01001713static unsigned int ref922x_pin_configs[10] = {
1714 0x01014010, 0x01016011, 0x01012012, 0x0221401f,
1715 0x01813122, 0x01011014, 0x01441030, 0x01c41030,
Matt2f2f4252005-04-13 14:45:30 +02001716 0x40000100, 0x40000100,
1717};
1718
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001719/*
1720 STAC 922X pin configs for
1721 102801A7
1722 102801AB
1723 102801A9
1724 102801D1
1725 102801D2
1726*/
1727static unsigned int dell_922x_d81_pin_configs[10] = {
1728 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1729 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1,
1730 0x01813122, 0x400001f2,
1731};
1732
1733/*
1734 STAC 922X pin configs for
1735 102801AC
1736 102801D0
1737*/
1738static unsigned int dell_922x_d82_pin_configs[10] = {
1739 0x02214030, 0x01a19021, 0x01111012, 0x01114010,
1740 0x02a19020, 0x01117011, 0x01451140, 0x400001f0,
1741 0x01813122, 0x400001f1,
1742};
1743
1744/*
1745 STAC 922X pin configs for
1746 102801BF
1747*/
1748static unsigned int dell_922x_m81_pin_configs[10] = {
1749 0x0321101f, 0x01112024, 0x01111222, 0x91174220,
1750 0x03a11050, 0x01116221, 0x90a70330, 0x01452340,
1751 0x40C003f1, 0x405003f0,
1752};
1753
1754/*
1755 STAC 9221 A1 pin configs for
1756 102801D7 (Dell XPS M1210)
1757*/
1758static unsigned int dell_922x_m82_pin_configs[10] = {
Jiang Zhe7f9310c2007-11-12 12:43:37 +01001759 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310,
1760 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001761 0x508003f3, 0x405003f4,
1762};
1763
Matt Porter403d1942005-11-29 15:00:51 +01001764static unsigned int d945gtp3_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001765 0x0221401f, 0x01a19022, 0x01813021, 0x01014010,
Matt Porter403d1942005-11-29 15:00:51 +01001766 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1767 0x02a19120, 0x40000100,
1768};
1769
1770static unsigned int d945gtp5_pin_configs[10] = {
Matt Porter869264c2006-01-25 19:20:50 +01001771 0x0221401f, 0x01011012, 0x01813024, 0x01014010,
1772 0x01a19021, 0x01016011, 0x01452130, 0x40000100,
Matt Porter403d1942005-11-29 15:00:51 +01001773 0x02a19320, 0x40000100,
1774};
1775
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001776static unsigned int intel_mac_v1_pin_configs[10] = {
1777 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
1778 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001779 0x400000fc, 0x400000fb,
1780};
1781
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001782static unsigned int intel_mac_v2_pin_configs[10] = {
1783 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1784 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
Sylvain FORETf16928f2007-04-27 14:22:36 +02001785 0x400000fc, 0x400000fb,
1786};
1787
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001788static unsigned int intel_mac_v3_pin_configs[10] = {
1789 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
1790 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
1791 0x400000fc, 0x400000fb,
1792};
1793
1794static unsigned int intel_mac_v4_pin_configs[10] = {
1795 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1796 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1797 0x400000fc, 0x400000fb,
1798};
1799
1800static unsigned int intel_mac_v5_pin_configs[10] = {
1801 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
1802 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
1803 0x400000fc, 0x400000fb,
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001804};
1805
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001806static unsigned int ecs202_pin_configs[10] = {
1807 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010,
1808 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1,
1809 0x9037012e, 0x40e000f2,
1810};
Takashi Iwai76c08822007-06-19 12:17:42 +02001811
Takashi Iwai19039bd2006-06-28 15:52:16 +02001812static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001813 [STAC_D945_REF] = ref922x_pin_configs,
Takashi Iwai19039bd2006-06-28 15:52:16 +02001814 [STAC_D945GTP3] = d945gtp3_pin_configs,
1815 [STAC_D945GTP5] = d945gtp5_pin_configs,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001816 [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
1817 [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
1818 [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
1819 [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
1820 [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001821 [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001822 /* for backward compatibility */
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001823 [STAC_MACMINI] = intel_mac_v3_pin_configs,
1824 [STAC_MACBOOK] = intel_mac_v5_pin_configs,
1825 [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
1826 [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
1827 [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
1828 [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001829 [STAC_ECS_202] = ecs202_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001830 [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs,
1831 [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs,
1832 [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs,
1833 [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
Matt Porter403d1942005-11-29 15:00:51 +01001834};
1835
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001836static const char *stac922x_models[STAC_922X_MODELS] = {
1837 [STAC_D945_REF] = "ref",
1838 [STAC_D945GTP5] = "5stack",
1839 [STAC_D945GTP3] = "3stack",
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02001840 [STAC_INTEL_MAC_V1] = "intel-mac-v1",
1841 [STAC_INTEL_MAC_V2] = "intel-mac-v2",
1842 [STAC_INTEL_MAC_V3] = "intel-mac-v3",
1843 [STAC_INTEL_MAC_V4] = "intel-mac-v4",
1844 [STAC_INTEL_MAC_V5] = "intel-mac-v5",
Nicolas Boichat536319a2008-07-21 22:18:01 +08001845 [STAC_INTEL_MAC_AUTO] = "intel-mac-auto",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001846 /* for backward compatibility */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001847 [STAC_MACMINI] = "macmini",
Takashi Iwai3fc24d82007-02-16 13:27:18 +01001848 [STAC_MACBOOK] = "macbook",
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01001849 [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
1850 [STAC_MACBOOK_PRO_V2] = "macbook-pro",
Sylvain FORETf16928f2007-04-27 14:22:36 +02001851 [STAC_IMAC_INTEL] = "imac-intel",
Takashi Iwai0dae0f82007-05-21 12:41:29 +02001852 [STAC_IMAC_INTEL_20] = "imac-intel-20",
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001853 [STAC_ECS_202] = "ecs202",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001854 [STAC_922X_DELL_D81] = "dell-d81",
1855 [STAC_922X_DELL_D82] = "dell-d82",
1856 [STAC_922X_DELL_M81] = "dell-m81",
1857 [STAC_922X_DELL_M82] = "dell-m82",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001858};
1859
1860static struct snd_pci_quirk stac922x_cfg_tbl[] = {
1861 /* SigmaTel reference board */
1862 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1863 "DFI LanParty", STAC_D945_REF),
1864 /* Intel 945G based systems */
1865 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
1866 "Intel D945G", STAC_D945GTP3),
1867 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
1868 "Intel D945G", STAC_D945GTP3),
1869 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
1870 "Intel D945G", STAC_D945GTP3),
1871 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
1872 "Intel D945G", STAC_D945GTP3),
1873 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
1874 "Intel D945G", STAC_D945GTP3),
1875 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
1876 "Intel D945G", STAC_D945GTP3),
1877 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
1878 "Intel D945G", STAC_D945GTP3),
1879 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
1880 "Intel D945G", STAC_D945GTP3),
1881 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
1882 "Intel D945G", STAC_D945GTP3),
1883 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
1884 "Intel D945G", STAC_D945GTP3),
1885 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
1886 "Intel D945G", STAC_D945GTP3),
1887 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
1888 "Intel D945G", STAC_D945GTP3),
1889 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
1890 "Intel D945G", STAC_D945GTP3),
1891 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
1892 "Intel D945G", STAC_D945GTP3),
1893 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
1894 "Intel D945G", STAC_D945GTP3),
1895 /* Intel D945G 5-stack systems */
1896 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
1897 "Intel D945G", STAC_D945GTP5),
1898 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
1899 "Intel D945G", STAC_D945GTP5),
1900 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
1901 "Intel D945G", STAC_D945GTP5),
1902 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
1903 "Intel D945G", STAC_D945GTP5),
1904 /* Intel 945P based systems */
1905 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
1906 "Intel D945P", STAC_D945GTP3),
1907 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
1908 "Intel D945P", STAC_D945GTP3),
1909 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
1910 "Intel D945P", STAC_D945GTP3),
1911 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
1912 "Intel D945P", STAC_D945GTP3),
1913 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
1914 "Intel D945P", STAC_D945GTP3),
1915 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
1916 "Intel D945P", STAC_D945GTP5),
1917 /* other systems */
Nicolas Boichat536319a2008-07-21 22:18:01 +08001918 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001919 SND_PCI_QUIRK(0x8384, 0x7680,
Nicolas Boichat536319a2008-07-21 22:18:01 +08001920 "Mac", STAC_INTEL_MAC_AUTO),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001921 /* Dell systems */
1922 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
1923 "unknown Dell", STAC_922X_DELL_D81),
1924 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
1925 "unknown Dell", STAC_922X_DELL_D81),
1926 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
1927 "unknown Dell", STAC_922X_DELL_D81),
1928 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
1929 "unknown Dell", STAC_922X_DELL_D82),
1930 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
1931 "unknown Dell", STAC_922X_DELL_M81),
1932 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
1933 "unknown Dell", STAC_922X_DELL_D82),
1934 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
1935 "unknown Dell", STAC_922X_DELL_D81),
1936 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
1937 "unknown Dell", STAC_922X_DELL_D81),
1938 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
1939 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03001940 /* ECS/PC Chips boards */
1941 SND_PCI_QUIRK(0x1019, 0x2144,
1942 "ECS/PC chips", STAC_ECS_202),
1943 SND_PCI_QUIRK(0x1019, 0x2608,
1944 "ECS/PC chips", STAC_ECS_202),
1945 SND_PCI_QUIRK(0x1019, 0x2633,
1946 "ECS/PC chips P17G/1333", STAC_ECS_202),
1947 SND_PCI_QUIRK(0x1019, 0x2811,
1948 "ECS/PC chips", STAC_ECS_202),
1949 SND_PCI_QUIRK(0x1019, 0x2812,
1950 "ECS/PC chips", STAC_ECS_202),
1951 SND_PCI_QUIRK(0x1019, 0x2813,
1952 "ECS/PC chips", STAC_ECS_202),
1953 SND_PCI_QUIRK(0x1019, 0x2814,
1954 "ECS/PC chips", STAC_ECS_202),
1955 SND_PCI_QUIRK(0x1019, 0x2815,
1956 "ECS/PC chips", STAC_ECS_202),
1957 SND_PCI_QUIRK(0x1019, 0x2816,
1958 "ECS/PC chips", STAC_ECS_202),
1959 SND_PCI_QUIRK(0x1019, 0x2817,
1960 "ECS/PC chips", STAC_ECS_202),
1961 SND_PCI_QUIRK(0x1019, 0x2818,
1962 "ECS/PC chips", STAC_ECS_202),
1963 SND_PCI_QUIRK(0x1019, 0x2819,
1964 "ECS/PC chips", STAC_ECS_202),
1965 SND_PCI_QUIRK(0x1019, 0x2820,
1966 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01001967 {} /* terminator */
1968};
1969
Matt Porter3cc08dc2006-01-23 15:27:49 +01001970static unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02001971 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1972 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
1973 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
1974 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01001975};
1976
Tobin Davis93ed1502006-09-01 21:03:12 +02001977static unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02001978 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
1979 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
1980 0x40000100, 0x40000100, 0x40000100, 0x40000100,
1981 0x40000100, 0x40000100
1982};
1983
Tobin Davis93ed1502006-09-01 21:03:12 +02001984static unsigned int d965_5st_pin_configs[14] = {
1985 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
1986 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
1987 0x40000100, 0x40000100, 0x40000100, 0x01442070,
1988 0x40000100, 0x40000100
1989};
1990
Tobin Davis4ff076e2007-08-07 11:48:12 +02001991static unsigned int dell_3st_pin_configs[14] = {
1992 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
1993 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001994 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02001995 0x40c003fc, 0x40000100
1996};
1997
Tobin Davis93ed1502006-09-01 21:03:12 +02001998static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01001999 [STAC_D965_REF] = ref927x_pin_configs,
2000 [STAC_D965_3ST] = d965_3st_pin_configs,
2001 [STAC_D965_5ST] = d965_5st_pin_configs,
2002 [STAC_DELL_3ST] = dell_3st_pin_configs,
2003 [STAC_DELL_BIOS] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002004};
2005
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002006static const char *stac927x_models[STAC_927X_MODELS] = {
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002007 [STAC_D965_REF] = "ref",
2008 [STAC_D965_3ST] = "3stack",
2009 [STAC_D965_5ST] = "5stack",
2010 [STAC_DELL_3ST] = "dell-3stack",
2011 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002012};
2013
2014static struct snd_pci_quirk stac927x_cfg_tbl[] = {
2015 /* SigmaTel reference board */
2016 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2017 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002018 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002019 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2020 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002021 /* 965 based 3 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002022 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST),
2023 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST),
2024 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST),
2025 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST),
2026 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST),
2027 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST),
2028 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST),
2029 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST),
2030 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST),
2031 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST),
2032 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST),
2033 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST),
2034 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST),
2035 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
2036 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
2037 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002038 /* Dell 3 stack systems */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002039 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002040 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002041 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2042 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002043 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002044 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
2045 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002046 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Takashi Iwai24918b62008-09-30 12:58:54 +02002047 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002048 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2049 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2050 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2051 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002052 /* 965 based 5 stack systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002053 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
2054 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
2055 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
2056 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST),
2057 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST),
2058 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST),
2059 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST),
2060 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST),
2061 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002062 {} /* terminator */
2063};
2064
Matt Porterf3302a52006-07-31 12:49:34 +02002065static unsigned int ref9205_pin_configs[12] = {
2066 0x40000100, 0x40000100, 0x01016011, 0x01014010,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002067 0x01813122, 0x01a19021, 0x01019020, 0x40000100,
Matt Porter8b657272006-10-26 17:12:59 +02002068 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
Matt Porterf3302a52006-07-31 12:49:34 +02002069};
2070
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002071/*
2072 STAC 9205 pin configs for
2073 102801F1
2074 102801F2
2075 102801FC
2076 102801FD
2077 10280204
2078 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002079 10280228 (Dell Vostro 1500)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002080*/
2081static unsigned int dell_9205_m42_pin_configs[12] = {
2082 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
2083 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9,
2084 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE,
2085};
2086
2087/*
2088 STAC 9205 pin configs for
2089 102801F9
2090 102801FA
2091 102801FE
2092 102801FF (Dell Precision M4300)
2093 10280206
2094 10280200
2095 10280201
2096*/
2097static unsigned int dell_9205_m43_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002098 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310,
2099 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9,
2100 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8,
2101};
2102
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002103static unsigned int dell_9205_m44_pin_configs[12] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002104 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310,
2105 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9,
2106 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe,
2107};
2108
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002109static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002110 [STAC_9205_REF] = ref9205_pin_configs,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002111 [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs,
2112 [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs,
2113 [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs,
Matt Porterf3302a52006-07-31 12:49:34 +02002114};
2115
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002116static const char *stac9205_models[STAC_9205_MODELS] = {
2117 [STAC_9205_REF] = "ref",
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002118 [STAC_9205_DELL_M42] = "dell-m42",
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002119 [STAC_9205_DELL_M43] = "dell-m43",
2120 [STAC_9205_DELL_M44] = "dell-m44",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002121};
2122
2123static struct snd_pci_quirk stac9205_cfg_tbl[] = {
2124 /* SigmaTel reference board */
2125 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2126 "DFI LanParty", STAC_9205_REF),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002127 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2128 "unknown Dell", STAC_9205_DELL_M42),
2129 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2130 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002131 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002132 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002133 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2134 "Dell Precision", STAC_9205_DELL_M43),
2135 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2136 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002137 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2138 "unknown Dell", STAC_9205_DELL_M42),
2139 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2140 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002141 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2142 "Dell Precision", STAC_9205_DELL_M43),
2143 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002144 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002145 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2146 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002147 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2148 "Dell Precision", STAC_9205_DELL_M43),
2149 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2150 "Dell Precision", STAC_9205_DELL_M43),
2151 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2152 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002153 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2154 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002155 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2156 "Dell Vostro 1500", STAC_9205_DELL_M42),
Matt Porterf3302a52006-07-31 12:49:34 +02002157 {} /* terminator */
2158};
2159
Richard Fish11b44bb2006-08-23 18:31:34 +02002160static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
2161{
2162 int i;
2163 struct sigmatel_spec *spec = codec->spec;
2164
2165 if (! spec->bios_pin_configs) {
2166 spec->bios_pin_configs = kcalloc(spec->num_pins,
2167 sizeof(*spec->bios_pin_configs), GFP_KERNEL);
2168 if (! spec->bios_pin_configs)
2169 return -ENOMEM;
2170 }
2171
2172 for (i = 0; i < spec->num_pins; i++) {
2173 hda_nid_t nid = spec->pin_nids[i];
2174 unsigned int pin_cfg;
2175
2176 pin_cfg = snd_hda_codec_read(codec, nid, 0,
2177 AC_VERB_GET_CONFIG_DEFAULT, 0x00);
2178 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n",
2179 nid, pin_cfg);
2180 spec->bios_pin_configs[i] = pin_cfg;
2181 }
2182
2183 return 0;
2184}
2185
Matthew Ranostay87d48362007-07-17 11:52:24 +02002186static void stac92xx_set_config_reg(struct hda_codec *codec,
2187 hda_nid_t pin_nid, unsigned int pin_config)
2188{
2189 int i;
2190 snd_hda_codec_write(codec, pin_nid, 0,
2191 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2192 pin_config & 0x000000ff);
2193 snd_hda_codec_write(codec, pin_nid, 0,
2194 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2195 (pin_config & 0x0000ff00) >> 8);
2196 snd_hda_codec_write(codec, pin_nid, 0,
2197 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2198 (pin_config & 0x00ff0000) >> 16);
2199 snd_hda_codec_write(codec, pin_nid, 0,
2200 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2201 pin_config >> 24);
2202 i = snd_hda_codec_read(codec, pin_nid, 0,
2203 AC_VERB_GET_CONFIG_DEFAULT,
2204 0x00);
2205 snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
2206 pin_nid, i);
2207}
2208
Matt2f2f4252005-04-13 14:45:30 +02002209static void stac92xx_set_config_regs(struct hda_codec *codec)
2210{
2211 int i;
2212 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002213
Matthew Ranostay87d48362007-07-17 11:52:24 +02002214 if (!spec->pin_configs)
2215 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002216
Matthew Ranostay87d48362007-07-17 11:52:24 +02002217 for (i = 0; i < spec->num_pins; i++)
2218 stac92xx_set_config_reg(codec, spec->pin_nids[i],
2219 spec->pin_configs[i]);
Matt2f2f4252005-04-13 14:45:30 +02002220}
Matt2f2f4252005-04-13 14:45:30 +02002221
Matt2f2f4252005-04-13 14:45:30 +02002222/*
2223 * Analog playback callbacks
2224 */
2225static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2226 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002227 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002228{
2229 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002230 if (spec->stream_delay)
2231 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002232 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2233 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002234}
2235
2236static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2237 struct hda_codec *codec,
2238 unsigned int stream_tag,
2239 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002240 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002241{
2242 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002243 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002244}
2245
2246static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2247 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002248 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002249{
2250 struct sigmatel_spec *spec = codec->spec;
2251 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2252}
2253
2254/*
Mattdabbed62005-06-14 10:19:34 +02002255 * Digital playback callbacks
2256 */
2257static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2258 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002259 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002260{
2261 struct sigmatel_spec *spec = codec->spec;
2262 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2263}
2264
2265static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2266 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002267 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002268{
2269 struct sigmatel_spec *spec = codec->spec;
2270 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2271}
2272
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002273static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2274 struct hda_codec *codec,
2275 unsigned int stream_tag,
2276 unsigned int format,
2277 struct snd_pcm_substream *substream)
2278{
2279 struct sigmatel_spec *spec = codec->spec;
2280 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2281 stream_tag, format, substream);
2282}
2283
Mattdabbed62005-06-14 10:19:34 +02002284
2285/*
Matt2f2f4252005-04-13 14:45:30 +02002286 * Analog capture callbacks
2287 */
2288static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2289 struct hda_codec *codec,
2290 unsigned int stream_tag,
2291 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002292 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002293{
2294 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002295 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002296
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002297 if (spec->powerdown_adcs) {
2298 msleep(40);
2299 snd_hda_codec_write_cache(codec, nid, 0,
2300 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2301 }
2302 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002303 return 0;
2304}
2305
2306static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2307 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002308 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002309{
2310 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002311 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002312
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002313 snd_hda_codec_cleanup_stream(codec, nid);
2314 if (spec->powerdown_adcs)
2315 snd_hda_codec_write_cache(codec, nid, 0,
2316 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02002317 return 0;
2318}
2319
Mattdabbed62005-06-14 10:19:34 +02002320static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
2321 .substreams = 1,
2322 .channels_min = 2,
2323 .channels_max = 2,
2324 /* NID is set in stac92xx_build_pcms */
2325 .ops = {
2326 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002327 .close = stac92xx_dig_playback_pcm_close,
2328 .prepare = stac92xx_dig_playback_pcm_prepare
Mattdabbed62005-06-14 10:19:34 +02002329 },
2330};
2331
2332static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
2333 .substreams = 1,
2334 .channels_min = 2,
2335 .channels_max = 2,
2336 /* NID is set in stac92xx_build_pcms */
2337};
2338
Matt2f2f4252005-04-13 14:45:30 +02002339static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
2340 .substreams = 1,
2341 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02002342 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02002343 .nid = 0x02, /* NID to query formats and rates */
2344 .ops = {
2345 .open = stac92xx_playback_pcm_open,
2346 .prepare = stac92xx_playback_pcm_prepare,
2347 .cleanup = stac92xx_playback_pcm_cleanup
2348 },
2349};
2350
Matt Porter3cc08dc2006-01-23 15:27:49 +01002351static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
2352 .substreams = 1,
2353 .channels_min = 2,
2354 .channels_max = 2,
2355 .nid = 0x06, /* NID to query formats and rates */
2356 .ops = {
2357 .open = stac92xx_playback_pcm_open,
2358 .prepare = stac92xx_playback_pcm_prepare,
2359 .cleanup = stac92xx_playback_pcm_cleanup
2360 },
2361};
2362
Matt2f2f4252005-04-13 14:45:30 +02002363static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02002364 .channels_min = 2,
2365 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002366 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02002367 .ops = {
2368 .prepare = stac92xx_capture_pcm_prepare,
2369 .cleanup = stac92xx_capture_pcm_cleanup
2370 },
2371};
2372
2373static int stac92xx_build_pcms(struct hda_codec *codec)
2374{
2375 struct sigmatel_spec *spec = codec->spec;
2376 struct hda_pcm *info = spec->pcm_rec;
2377
2378 codec->num_pcms = 1;
2379 codec->pcm_info = info;
2380
Mattc7d4b2f2005-06-27 14:59:41 +02002381 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02002382 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Matt2f2f4252005-04-13 14:45:30 +02002383 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002384 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02002385 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01002386
2387 if (spec->alt_switch) {
2388 codec->num_pcms++;
2389 info++;
2390 info->name = "STAC92xx Analog Alt";
2391 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
2392 }
Matt2f2f4252005-04-13 14:45:30 +02002393
Mattdabbed62005-06-14 10:19:34 +02002394 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
2395 codec->num_pcms++;
2396 info++;
2397 info->name = "STAC92xx Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002398 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Mattdabbed62005-06-14 10:19:34 +02002399 if (spec->multiout.dig_out_nid) {
2400 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
2401 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2402 }
2403 if (spec->dig_in_nid) {
2404 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
2405 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2406 }
2407 }
2408
Matt2f2f4252005-04-13 14:45:30 +02002409 return 0;
2410}
2411
Takashi Iwaic960a032006-03-23 17:06:28 +01002412static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid)
2413{
2414 unsigned int pincap = snd_hda_param_read(codec, nid,
2415 AC_PAR_PIN_CAP);
2416 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
2417 if (pincap & AC_PINCAP_VREF_100)
2418 return AC_PINCTL_VREF_100;
2419 if (pincap & AC_PINCAP_VREF_80)
2420 return AC_PINCTL_VREF_80;
2421 if (pincap & AC_PINCAP_VREF_50)
2422 return AC_PINCTL_VREF_50;
2423 if (pincap & AC_PINCAP_VREF_GRD)
2424 return AC_PINCTL_VREF_GRD;
2425 return 0;
2426}
2427
Matt Porter403d1942005-11-29 15:00:51 +01002428static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
2429
2430{
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002431 snd_hda_codec_write_cache(codec, nid, 0,
2432 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01002433}
2434
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002435#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
2436
2437static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2438 struct snd_ctl_elem_value *ucontrol)
2439{
2440 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2441 struct sigmatel_spec *spec = codec->spec;
2442
2443 ucontrol->value.integer.value[0] = spec->hp_switch;
2444 return 0;
2445}
2446
2447static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2448 struct snd_ctl_elem_value *ucontrol)
2449{
2450 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2451 struct sigmatel_spec *spec = codec->spec;
2452
2453 spec->hp_switch = ucontrol->value.integer.value[0];
2454
2455 /* check to be sure that the ports are upto date with
2456 * switch changes
2457 */
2458 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2459
2460 return 1;
2461}
2462
Takashi Iwaia5ce8892007-07-23 15:42:26 +02002463#define stac92xx_io_switch_info snd_ctl_boolean_mono_info
Matt Porter403d1942005-11-29 15:00:51 +01002464
2465static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2466{
2467 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2468 struct sigmatel_spec *spec = codec->spec;
2469 int io_idx = kcontrol-> private_value & 0xff;
2470
2471 ucontrol->value.integer.value[0] = spec->io_switch[io_idx];
2472 return 0;
2473}
2474
2475static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2476{
2477 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2478 struct sigmatel_spec *spec = codec->spec;
2479 hda_nid_t nid = kcontrol->private_value >> 8;
2480 int io_idx = kcontrol-> private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002481 unsigned short val = !!ucontrol->value.integer.value[0];
Matt Porter403d1942005-11-29 15:00:51 +01002482
2483 spec->io_switch[io_idx] = val;
2484
2485 if (val)
2486 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01002487 else {
2488 unsigned int pinctl = AC_PINCTL_IN_EN;
2489 if (io_idx) /* set VREF for mic */
2490 pinctl |= stac92xx_get_vref(codec, nid);
2491 stac92xx_auto_set_pinctl(codec, nid, pinctl);
2492 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01002493
2494 /* check the auto-mute again: we need to mute/unmute the speaker
2495 * appropriately according to the pin direction
2496 */
2497 if (spec->hp_detect)
2498 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
2499
Matt Porter403d1942005-11-29 15:00:51 +01002500 return 1;
2501}
2502
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002503#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
2504
2505static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
2506 struct snd_ctl_elem_value *ucontrol)
2507{
2508 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2509 struct sigmatel_spec *spec = codec->spec;
2510
2511 ucontrol->value.integer.value[0] = spec->clfe_swap;
2512 return 0;
2513}
2514
2515static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2516 struct snd_ctl_elem_value *ucontrol)
2517{
2518 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2519 struct sigmatel_spec *spec = codec->spec;
2520 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002521 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002522
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002523 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002524 return 0;
2525
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002526 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002527
2528 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
2529 spec->clfe_swap ? 0x4 : 0x0);
2530
2531 return 1;
2532}
2533
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002534#define STAC_CODEC_HP_SWITCH(xname) \
2535 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2536 .name = xname, \
2537 .index = 0, \
2538 .info = stac92xx_hp_switch_info, \
2539 .get = stac92xx_hp_switch_get, \
2540 .put = stac92xx_hp_switch_put, \
2541 }
2542
Matt Porter403d1942005-11-29 15:00:51 +01002543#define STAC_CODEC_IO_SWITCH(xname, xpval) \
2544 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2545 .name = xname, \
2546 .index = 0, \
2547 .info = stac92xx_io_switch_info, \
2548 .get = stac92xx_io_switch_get, \
2549 .put = stac92xx_io_switch_put, \
2550 .private_value = xpval, \
2551 }
2552
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002553#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
2554 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2555 .name = xname, \
2556 .index = 0, \
2557 .info = stac92xx_clfe_switch_info, \
2558 .get = stac92xx_clfe_switch_get, \
2559 .put = stac92xx_clfe_switch_put, \
2560 .private_value = xpval, \
2561 }
Matt Porter403d1942005-11-29 15:00:51 +01002562
Mattc7d4b2f2005-06-27 14:59:41 +02002563enum {
2564 STAC_CTL_WIDGET_VOL,
2565 STAC_CTL_WIDGET_MUTE,
Matthew Ranostay09a99952008-01-24 11:49:21 +01002566 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002567 STAC_CTL_WIDGET_AMP_MUX,
2568 STAC_CTL_WIDGET_AMP_VOL,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002569 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01002570 STAC_CTL_WIDGET_IO_SWITCH,
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002571 STAC_CTL_WIDGET_CLFE_SWITCH
Mattc7d4b2f2005-06-27 14:59:41 +02002572};
2573
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002574static struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02002575 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2576 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01002577 STAC_MONO_MUX,
Matthew Ranostay89385032008-09-11 09:49:39 -04002578 STAC_AMP_MUX,
2579 STAC_AMP_VOL(NULL, 0, 0, 0, 0),
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002580 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01002581 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002582 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02002583};
2584
2585/* add dynamic controls */
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002586static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type,
2587 int idx, const char *name, unsigned long val)
Mattc7d4b2f2005-06-27 14:59:41 +02002588{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002589 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02002590
2591 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2592 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2593
2594 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2595 if (! knew)
2596 return -ENOMEM;
2597 if (spec->kctl_alloc) {
2598 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2599 kfree(spec->kctl_alloc);
2600 }
2601 spec->kctl_alloc = knew;
2602 spec->num_kctl_alloc = num;
2603 }
2604
2605 knew = &spec->kctl_alloc[spec->num_kctl_used];
2606 *knew = stac92xx_control_templates[type];
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002607 knew->index = idx;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02002608 knew->name = kstrdup(name, GFP_KERNEL);
Mattc7d4b2f2005-06-27 14:59:41 +02002609 if (! knew->name)
2610 return -ENOMEM;
2611 knew->private_value = val;
2612 spec->num_kctl_used++;
2613 return 0;
2614}
2615
Matthew Ranostay4682eee2008-08-15 07:43:24 +02002616
2617/* add dynamic controls */
2618static int stac92xx_add_control(struct sigmatel_spec *spec, int type,
2619 const char *name, unsigned long val)
2620{
2621 return stac92xx_add_control_idx(spec, type, 0, name, val);
2622}
2623
Matt Porter403d1942005-11-29 15:00:51 +01002624/* flag inputs as additional dynamic lineouts */
2625static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg)
2626{
2627 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002628 unsigned int wcaps, wtype;
2629 int i, num_dacs = 0;
2630
2631 /* use the wcaps cache to count all DACs available for line-outs */
2632 for (i = 0; i < codec->num_nodes; i++) {
2633 wcaps = codec->wcaps[i];
2634 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002635
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002636 if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
2637 num_dacs++;
2638 }
Matt Porter403d1942005-11-29 15:00:51 +01002639
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002640 snd_printdd("%s: total dac count=%d\n", __func__, num_dacs);
2641
Matt Porter403d1942005-11-29 15:00:51 +01002642 switch (cfg->line_outs) {
2643 case 3:
2644 /* add line-in as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002645 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002646 cfg->line_out_pins[cfg->line_outs] =
2647 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002648 spec->line_switch = 1;
2649 cfg->line_outs++;
2650 }
2651 break;
2652 case 2:
2653 /* add line-in as clfe and mic as side */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002654 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002655 cfg->line_out_pins[cfg->line_outs] =
2656 cfg->input_pins[AUTO_PIN_LINE];
Matt Porter403d1942005-11-29 15:00:51 +01002657 spec->line_switch = 1;
2658 cfg->line_outs++;
2659 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002660 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002661 cfg->line_out_pins[cfg->line_outs] =
2662 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002663 spec->mic_switch = 1;
2664 cfg->line_outs++;
2665 }
2666 break;
2667 case 1:
2668 /* add line-in as surr and mic as clfe */
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002669 if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) {
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 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002675 if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) {
Takashi Iwaic480f792007-09-03 09:43:38 +02002676 cfg->line_out_pins[cfg->line_outs] =
2677 cfg->input_pins[AUTO_PIN_MIC];
Matt Porter403d1942005-11-29 15:00:51 +01002678 spec->mic_switch = 1;
2679 cfg->line_outs++;
2680 }
2681 break;
2682 }
2683
2684 return 0;
2685}
2686
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002687
2688static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2689{
2690 int i;
2691
2692 for (i = 0; i < spec->multiout.num_dacs; i++) {
2693 if (spec->multiout.dac_nids[i] == nid)
2694 return 1;
2695 }
2696
2697 return 0;
2698}
2699
Matt Porter3cc08dc2006-01-23 15:27:49 +01002700/*
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002701 * Fill in the dac_nids table from the parsed pin configuration
2702 * This function only works when every pin in line_out_pins[]
2703 * contains atleast one DAC in its connection list. Some 92xx
2704 * codecs are not connected directly to a DAC, such as the 9200
2705 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01002706 */
Takashi Iwai19039bd2006-06-28 15:52:16 +02002707static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaidf802952007-07-02 19:18:00 +02002708 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002709{
2710 struct sigmatel_spec *spec = codec->spec;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002711 int i, j, conn_len = 0;
2712 hda_nid_t nid, conn[HDA_MAX_CONNECTIONS];
2713 unsigned int wcaps, wtype;
2714
Mattc7d4b2f2005-06-27 14:59:41 +02002715 for (i = 0; i < cfg->line_outs; i++) {
2716 nid = cfg->line_out_pins[i];
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002717 conn_len = snd_hda_get_connections(codec, nid, conn,
2718 HDA_MAX_CONNECTIONS);
2719 for (j = 0; j < conn_len; j++) {
2720 wcaps = snd_hda_param_read(codec, conn[j],
2721 AC_PAR_AUDIO_WIDGET_CAP);
2722 wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002723 if (wtype != AC_WID_AUD_OUT ||
2724 (wcaps & AC_WCAP_DIGITAL))
2725 continue;
2726 /* conn[j] is a DAC routed to this line-out */
2727 if (!is_in_dac_nids(spec, conn[j]))
2728 break;
2729 }
2730
2731 if (j == conn_len) {
Takashi Iwaidf802952007-07-02 19:18:00 +02002732 if (spec->multiout.num_dacs > 0) {
2733 /* we have already working output pins,
2734 * so let's drop the broken ones again
2735 */
2736 cfg->line_outs = spec->multiout.num_dacs;
2737 break;
2738 }
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002739 /* error out, no available DAC found */
2740 snd_printk(KERN_ERR
2741 "%s: No available DAC for pin 0x%x\n",
2742 __func__, nid);
2743 return -ENODEV;
2744 }
2745
2746 spec->multiout.dac_nids[i] = conn[j];
2747 spec->multiout.num_dacs++;
2748 if (conn_len > 1) {
2749 /* select this DAC in the pin's input mux */
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002750 snd_hda_codec_write_cache(codec, nid, 0,
2751 AC_VERB_SET_CONNECT_SEL, j);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002752
2753 }
Mattc7d4b2f2005-06-27 14:59:41 +02002754 }
2755
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002756 snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
2757 spec->multiout.num_dacs,
2758 spec->multiout.dac_nids[0],
2759 spec->multiout.dac_nids[1],
2760 spec->multiout.dac_nids[2],
2761 spec->multiout.dac_nids[3],
2762 spec->multiout.dac_nids[4]);
Mattc7d4b2f2005-06-27 14:59:41 +02002763 return 0;
2764}
2765
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002766/* create volume control/switch for the given prefx type */
2767static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
2768{
2769 char name[32];
2770 int err;
2771
2772 sprintf(name, "%s Playback Volume", pfx);
2773 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
2774 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2775 if (err < 0)
2776 return err;
2777 sprintf(name, "%s Playback Switch", pfx);
2778 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
2779 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
2780 if (err < 0)
2781 return err;
2782 return 0;
2783}
2784
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002785static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
2786{
2787 if (!spec->multiout.hp_nid)
2788 spec->multiout.hp_nid = nid;
2789 else if (spec->multiout.num_dacs > 4) {
2790 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
2791 return 1;
2792 } else {
2793 spec->multiout.dac_nids[spec->multiout.num_dacs] = nid;
2794 spec->multiout.num_dacs++;
2795 }
2796 return 0;
2797}
2798
2799static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
2800{
2801 if (is_in_dac_nids(spec, nid))
2802 return 1;
2803 if (spec->multiout.hp_nid == nid)
2804 return 1;
2805 return 0;
2806}
2807
Mattc7d4b2f2005-06-27 14:59:41 +02002808/* add playback controls from the parsed DAC table */
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002809static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai19039bd2006-06-28 15:52:16 +02002810 const struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002811{
Takashi Iwai19039bd2006-06-28 15:52:16 +02002812 static const char *chname[4] = {
2813 "Front", "Surround", NULL /*CLFE*/, "Side"
2814 };
Mattc7d4b2f2005-06-27 14:59:41 +02002815 hda_nid_t nid;
2816 int i, err;
2817
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002818 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002819 unsigned int wid_caps, pincap;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002820
2821
Takashi Iwai40ac8c42008-02-29 14:16:17 +01002822 for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
Matt Porter403d1942005-11-29 15:00:51 +01002823 if (!spec->multiout.dac_nids[i])
Mattc7d4b2f2005-06-27 14:59:41 +02002824 continue;
2825
2826 nid = spec->multiout.dac_nids[i];
2827
2828 if (i == 2) {
2829 /* Center/LFE */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002830 err = create_controls(spec, "Center", nid, 1);
2831 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002832 return err;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002833 err = create_controls(spec, "LFE", nid, 2);
2834 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002835 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02002836
2837 wid_caps = get_wcaps(codec, nid);
2838
2839 if (wid_caps & AC_WCAP_LR_SWAP) {
2840 err = stac92xx_add_control(spec,
2841 STAC_CTL_WIDGET_CLFE_SWITCH,
2842 "Swap Center/LFE Playback Switch", nid);
2843
2844 if (err < 0)
2845 return err;
2846 }
2847
Mattc7d4b2f2005-06-27 14:59:41 +02002848 } else {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002849 err = create_controls(spec, chname[i], nid, 3);
2850 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02002851 return err;
2852 }
2853 }
2854
Matthew Ranostayfedb7562008-09-23 21:46:30 -04002855 if ((spec->multiout.num_dacs - cfg->line_outs) > 0 &&
2856 cfg->hp_outs && !spec->multiout.hp_nid)
2857 spec->multiout.hp_nid = nid;
2858
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02002859 if (cfg->hp_outs > 1) {
2860 err = stac92xx_add_control(spec,
2861 STAC_CTL_WIDGET_HP_SWITCH,
2862 "Headphone as Line Out Switch", 0);
2863 if (err < 0)
2864 return err;
2865 }
2866
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002867 if (spec->line_switch) {
2868 nid = cfg->input_pins[AUTO_PIN_LINE];
2869 pincap = snd_hda_param_read(codec, nid,
2870 AC_PAR_PIN_CAP);
2871 if (pincap & AC_PINCAP_OUT) {
2872 err = stac92xx_add_control(spec,
2873 STAC_CTL_WIDGET_IO_SWITCH,
2874 "Line In as Output Switch", nid << 8);
2875 if (err < 0)
2876 return err;
2877 }
2878 }
Matt Porter403d1942005-11-29 15:00:51 +01002879
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002880 if (spec->mic_switch) {
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002881 unsigned int def_conf;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002882 unsigned int mic_pin = AUTO_PIN_MIC;
2883again:
2884 nid = cfg->input_pins[mic_pin];
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002885 def_conf = snd_hda_codec_read(codec, nid, 0,
2886 AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002887 /* some laptops have an internal analog microphone
2888 * which can't be used as a output */
2889 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
2890 pincap = snd_hda_param_read(codec, nid,
2891 AC_PAR_PIN_CAP);
2892 if (pincap & AC_PINCAP_OUT) {
2893 err = stac92xx_add_control(spec,
2894 STAC_CTL_WIDGET_IO_SWITCH,
2895 "Mic as Output Switch", (nid << 8) | 1);
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002896 nid = snd_hda_codec_read(codec, nid, 0,
2897 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2898 if (!check_in_dac_nids(spec, nid))
2899 add_spec_dacs(spec, nid);
Matthew Ranostaycace16f2008-01-30 14:58:38 +01002900 if (err < 0)
2901 return err;
2902 }
Matthew Ranostayae0afd82008-02-22 17:55:05 +01002903 } else if (mic_pin == AUTO_PIN_MIC) {
2904 mic_pin = AUTO_PIN_FRONT_MIC;
2905 goto again;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01002906 }
2907 }
Matt Porter403d1942005-11-29 15:00:51 +01002908
Mattc7d4b2f2005-06-27 14:59:41 +02002909 return 0;
2910}
2911
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002912/* add playback controls for Speaker and HP outputs */
2913static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
2914 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02002915{
2916 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02002917 hda_nid_t nid;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002918 int i, old_num_dacs, err;
Mattc7d4b2f2005-06-27 14:59:41 +02002919
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002920 old_num_dacs = spec->multiout.num_dacs;
2921 for (i = 0; i < cfg->hp_outs; i++) {
2922 unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]);
2923 if (wid_caps & AC_WCAP_UNSOL_CAP)
2924 spec->hp_detect = 1;
2925 nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
2926 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2927 if (check_in_dac_nids(spec, nid))
2928 nid = 0;
2929 if (! nid)
Mattc7d4b2f2005-06-27 14:59:41 +02002930 continue;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002931 add_spec_dacs(spec, nid);
2932 }
2933 for (i = 0; i < cfg->speaker_outs; i++) {
Steve Longerbeam7b0438992007-05-03 20:50:03 +02002934 nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002935 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2936 if (check_in_dac_nids(spec, nid))
2937 nid = 0;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002938 if (! nid)
2939 continue;
2940 add_spec_dacs(spec, nid);
Mattc7d4b2f2005-06-27 14:59:41 +02002941 }
Matthew Ranostay1b290a52007-07-12 15:17:34 +02002942 for (i = 0; i < cfg->line_outs; i++) {
2943 nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
2944 AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
2945 if (check_in_dac_nids(spec, nid))
2946 nid = 0;
2947 if (! nid)
2948 continue;
2949 add_spec_dacs(spec, nid);
2950 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002951 for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
2952 static const char *pfxs[] = {
2953 "Speaker", "External Speaker", "Speaker2",
2954 };
2955 err = create_controls(spec, pfxs[i - old_num_dacs],
2956 spec->multiout.dac_nids[i], 3);
2957 if (err < 0)
2958 return err;
2959 }
2960 if (spec->multiout.hp_nid) {
Takashi Iwai2626a262008-03-14 09:18:32 +01002961 err = create_controls(spec, "Headphone",
2962 spec->multiout.hp_nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02002963 if (err < 0)
2964 return err;
2965 }
Mattc7d4b2f2005-06-27 14:59:41 +02002966
2967 return 0;
2968}
2969
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002970/* labels for mono mux outputs */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002971static const char *stac92xx_mono_labels[4] = {
2972 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002973};
2974
2975/* create mono mux for mono out on capable codecs */
2976static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
2977{
2978 struct sigmatel_spec *spec = codec->spec;
2979 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
2980 int i, num_cons;
2981 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
2982
2983 num_cons = snd_hda_get_connections(codec,
2984 spec->mono_nid,
2985 con_lst,
2986 HDA_MAX_NUM_INPUTS);
2987 if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
2988 return -EINVAL;
2989
2990 for (i = 0; i < num_cons; i++) {
2991 mono_mux->items[mono_mux->num_items].label =
2992 stac92xx_mono_labels[i];
2993 mono_mux->items[mono_mux->num_items].index = i;
2994 mono_mux->num_items++;
2995 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01002996
2997 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
2998 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01002999}
3000
Matthew Ranostay89385032008-09-11 09:49:39 -04003001/* labels for amp mux outputs */
3002static const char *stac92xx_amp_labels[3] = {
3003 "Front Microphone", "Microphone", "Line In"
3004};
3005
3006/* create amp out controls mux on capable codecs */
3007static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec)
3008{
3009 struct sigmatel_spec *spec = codec->spec;
3010 struct hda_input_mux *amp_mux = &spec->private_amp_mux;
3011 int i, err;
3012
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003013 for (i = 0; i < spec->num_amps; i++) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003014 amp_mux->items[amp_mux->num_items].label =
3015 stac92xx_amp_labels[i];
3016 amp_mux->items[amp_mux->num_items].index = i;
3017 amp_mux->num_items++;
3018 }
3019
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003020 if (spec->num_amps > 1) {
3021 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX,
3022 "Amp Selector Capture Switch", 0);
3023 if (err < 0)
3024 return err;
3025 }
Matthew Ranostay89385032008-09-11 09:49:39 -04003026 return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL,
3027 "Amp Capture Volume",
3028 HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT));
3029}
3030
3031
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003032/* create PC beep volume controls */
3033static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3034 hda_nid_t nid)
3035{
3036 struct sigmatel_spec *spec = codec->spec;
3037 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3038 int err;
3039
3040 /* check for mute support for the the amp */
3041 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3042 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3043 "PC Beep Playback Switch",
3044 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3045 if (err < 0)
3046 return err;
3047 }
3048
3049 /* check to see if there is volume support for the amp */
3050 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3051 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
3052 "PC Beep Playback Volume",
3053 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3054 if (err < 0)
3055 return err;
3056 }
3057 return 0;
3058}
3059
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003060static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
3061{
3062 struct sigmatel_spec *spec = codec->spec;
3063 int wcaps, nid, i, err = 0;
3064
3065 for (i = 0; i < spec->num_muxes; i++) {
3066 nid = spec->mux_nids[i];
3067 wcaps = get_wcaps(codec, nid);
3068
3069 if (wcaps & AC_WCAP_OUT_AMP) {
3070 err = stac92xx_add_control_idx(spec,
3071 STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume",
3072 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3073 if (err < 0)
3074 return err;
3075 }
3076 }
3077 return 0;
3078};
3079
Matthew Ranostayd9737752008-09-07 12:03:41 +02003080static const char *stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04003081 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02003082};
3083
3084static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
3085{
3086 struct sigmatel_spec *spec = codec->spec;
3087 struct hda_input_mux *spdif_mux = &spec->private_smux;
Matthew Ranostay65973632008-09-16 10:39:37 -04003088 const char **labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003089 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04003090 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003091
3092 num_cons = snd_hda_get_connections(codec,
3093 spec->smux_nids[0],
3094 con_lst,
3095 HDA_MAX_NUM_INPUTS);
Matthew Ranostay65973632008-09-16 10:39:37 -04003096 if (!num_cons)
Matthew Ranostayd9737752008-09-07 12:03:41 +02003097 return -EINVAL;
3098
Matthew Ranostay65973632008-09-16 10:39:37 -04003099 if (!labels)
3100 labels = stac92xx_spdif_labels;
3101
Matthew Ranostayd9737752008-09-07 12:03:41 +02003102 for (i = 0; i < num_cons; i++) {
Matthew Ranostay65973632008-09-16 10:39:37 -04003103 spdif_mux->items[spdif_mux->num_items].label = labels[i];
Matthew Ranostayd9737752008-09-07 12:03:41 +02003104 spdif_mux->items[spdif_mux->num_items].index = i;
3105 spdif_mux->num_items++;
3106 }
3107
3108 return 0;
3109}
3110
Matt Porter8b657272006-10-26 17:12:59 +02003111/* labels for dmic mux inputs */
Adrian Bunkddc2cec2006-11-20 12:03:44 +01003112static const char *stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02003113 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
3114 "Digital Mic 3", "Digital Mic 4"
3115};
3116
3117/* create playback/capture controls for input pins on dmic capable codecs */
3118static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
3119 const struct auto_pin_cfg *cfg)
3120{
3121 struct sigmatel_spec *spec = codec->spec;
3122 struct hda_input_mux *dimux = &spec->private_dimux;
3123 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003124 int err, i, j;
3125 char name[32];
Matt Porter8b657272006-10-26 17:12:59 +02003126
3127 dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
3128 dimux->items[dimux->num_items].index = 0;
3129 dimux->num_items++;
3130
3131 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003132 hda_nid_t nid;
Matt Porter8b657272006-10-26 17:12:59 +02003133 int index;
3134 int num_cons;
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003135 unsigned int wcaps;
Matt Porter8b657272006-10-26 17:12:59 +02003136 unsigned int def_conf;
3137
3138 def_conf = snd_hda_codec_read(codec,
3139 spec->dmic_nids[i],
3140 0,
3141 AC_VERB_GET_CONFIG_DEFAULT,
3142 0);
3143 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
3144 continue;
3145
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003146 nid = spec->dmic_nids[i];
Matt Porter8b657272006-10-26 17:12:59 +02003147 num_cons = snd_hda_get_connections(codec,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01003148 spec->dmux_nids[0],
Matt Porter8b657272006-10-26 17:12:59 +02003149 con_lst,
3150 HDA_MAX_NUM_INPUTS);
3151 for (j = 0; j < num_cons; j++)
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003152 if (con_lst[j] == nid) {
Matt Porter8b657272006-10-26 17:12:59 +02003153 index = j;
3154 goto found;
3155 }
3156 continue;
3157found:
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003158 wcaps = get_wcaps(codec, nid) &
3159 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003160
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003161 if (wcaps) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003162 sprintf(name, "%s Capture Volume",
3163 stac92xx_dmic_labels[dimux->num_items]);
3164
3165 err = stac92xx_add_control(spec,
3166 STAC_CTL_WIDGET_VOL,
3167 name,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003168 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3169 (wcaps & AC_WCAP_OUT_AMP) ?
3170 HDA_OUTPUT : HDA_INPUT));
Matthew Ranostay0678acc2008-01-08 12:10:50 +01003171 if (err < 0)
3172 return err;
3173 }
3174
Matt Porter8b657272006-10-26 17:12:59 +02003175 dimux->items[dimux->num_items].label =
3176 stac92xx_dmic_labels[dimux->num_items];
3177 dimux->items[dimux->num_items].index = index;
3178 dimux->num_items++;
3179 }
3180
3181 return 0;
3182}
3183
Mattc7d4b2f2005-06-27 14:59:41 +02003184/* create playback/capture controls for input pins */
3185static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
3186{
3187 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003188 struct hda_input_mux *imux = &spec->private_imux;
3189 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
3190 int i, j, k;
3191
3192 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003193 int index;
Mattc7d4b2f2005-06-27 14:59:41 +02003194
Takashi Iwai314634b2006-09-21 11:56:18 +02003195 if (!cfg->input_pins[i])
3196 continue;
3197 index = -1;
3198 for (j = 0; j < spec->num_muxes; j++) {
3199 int num_cons;
3200 num_cons = snd_hda_get_connections(codec,
3201 spec->mux_nids[j],
3202 con_lst,
3203 HDA_MAX_NUM_INPUTS);
3204 for (k = 0; k < num_cons; k++)
3205 if (con_lst[k] == cfg->input_pins[i]) {
3206 index = k;
3207 goto found;
3208 }
Mattc7d4b2f2005-06-27 14:59:41 +02003209 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003210 continue;
3211 found:
3212 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
3213 imux->items[imux->num_items].index = index;
3214 imux->num_items++;
Mattc7d4b2f2005-06-27 14:59:41 +02003215 }
3216
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003217 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02003218 /*
3219 * Set the current input for the muxes.
3220 * The STAC9221 has two input muxes with identical source
3221 * NID lists. Hopefully this won't get confused.
3222 */
3223 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003224 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
3225 AC_VERB_SET_CONNECT_SEL,
3226 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003227 }
3228 }
3229
Mattc7d4b2f2005-06-27 14:59:41 +02003230 return 0;
3231}
3232
Mattc7d4b2f2005-06-27 14:59:41 +02003233static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
3234{
3235 struct sigmatel_spec *spec = codec->spec;
3236 int i;
3237
3238 for (i = 0; i < spec->autocfg.line_outs; i++) {
3239 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3240 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
3241 }
3242}
3243
3244static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
3245{
3246 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003247 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003248
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003249 for (i = 0; i < spec->autocfg.hp_outs; i++) {
3250 hda_nid_t pin;
3251 pin = spec->autocfg.hp_pins[i];
3252 if (pin) /* connect to front */
3253 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
3254 }
3255 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3256 hda_nid_t pin;
3257 pin = spec->autocfg.speaker_pins[i];
3258 if (pin) /* connect to front */
3259 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
3260 }
Mattc7d4b2f2005-06-27 14:59:41 +02003261}
3262
Matt Porter3cc08dc2006-01-23 15:27:49 +01003263static 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 +02003264{
3265 struct sigmatel_spec *spec = codec->spec;
3266 int err;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003267 int hp_speaker_swap = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003268
Matt Porter8b657272006-10-26 17:12:59 +02003269 if ((err = snd_hda_parse_pin_def_config(codec,
3270 &spec->autocfg,
3271 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003272 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003273 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01003274 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02003275
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003276 /* If we have no real line-out pin and multiple hp-outs, HPs should
3277 * be set up as multi-channel outputs.
3278 */
3279 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3280 spec->autocfg.hp_outs > 1) {
3281 /* Copy hp_outs to line_outs, backup line_outs in
3282 * speaker_outs so that the following routines can handle
3283 * HP pins as primary outputs.
3284 */
3285 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
3286 sizeof(spec->autocfg.line_out_pins));
3287 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
3288 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
3289 sizeof(spec->autocfg.hp_pins));
3290 spec->autocfg.line_outs = spec->autocfg.hp_outs;
3291 hp_speaker_swap = 1;
3292 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003293 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003294 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
3295 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003296 u32 caps = query_amp_caps(codec,
3297 spec->autocfg.mono_out_pin, dir);
3298 hda_nid_t conn_list[1];
3299
3300 /* get the mixer node and then the mono mux if it exists */
3301 if (snd_hda_get_connections(codec,
3302 spec->autocfg.mono_out_pin, conn_list, 1) &&
3303 snd_hda_get_connections(codec, conn_list[0],
3304 conn_list, 1)) {
3305
3306 int wcaps = get_wcaps(codec, conn_list[0]);
3307 int wid_type = (wcaps & AC_WCAP_TYPE)
3308 >> AC_WCAP_TYPE_SHIFT;
3309 /* LR swap check, some stac925x have a mux that
3310 * changes the DACs output path instead of the
3311 * mono-mux path.
3312 */
3313 if (wid_type == AC_WID_AUD_SEL &&
3314 !(wcaps & AC_WCAP_LR_SWAP))
3315 spec->mono_nid = conn_list[0];
3316 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003317 if (dir) {
3318 hda_nid_t nid = spec->autocfg.mono_out_pin;
3319
3320 /* most mono outs have a least a mute/unmute switch */
3321 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
3322 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
3323 "Mono Playback Switch",
3324 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01003325 if (err < 0)
3326 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003327 /* check for volume support for the amp */
3328 if ((caps & AC_AMPCAP_NUM_STEPS)
3329 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
3330 err = stac92xx_add_control(spec,
3331 STAC_CTL_WIDGET_VOL,
3332 "Mono Playback Volume",
3333 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
3334 if (err < 0)
3335 return err;
3336 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01003337 }
3338
3339 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
3340 AC_PINCTL_OUT_EN);
3341 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003342
Matt Porter403d1942005-11-29 15:00:51 +01003343 if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
3344 return err;
Takashi Iwai19039bd2006-06-28 15:52:16 +02003345 if (spec->multiout.num_dacs == 0)
3346 if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3347 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003348
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003349 err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg);
3350
3351 if (err < 0)
3352 return err;
3353
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003354 /* setup analog beep controls */
3355 if (spec->anabeep_nid > 0) {
3356 err = stac92xx_auto_create_beep_ctls(codec,
3357 spec->anabeep_nid);
3358 if (err < 0)
3359 return err;
3360 }
3361
3362 /* setup digital beep controls and input device */
3363#ifdef CONFIG_SND_HDA_INPUT_BEEP
3364 if (spec->digbeep_nid > 0) {
3365 hda_nid_t nid = spec->digbeep_nid;
3366
3367 err = stac92xx_auto_create_beep_ctls(codec, nid);
3368 if (err < 0)
3369 return err;
3370 err = snd_hda_attach_beep_device(codec, nid);
3371 if (err < 0)
3372 return err;
3373 }
3374#endif
3375
Jiang Zhebcecd9b2007-11-12 12:57:03 +01003376 if (hp_speaker_swap == 1) {
3377 /* Restore the hp_outs and line_outs */
3378 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
3379 sizeof(spec->autocfg.line_out_pins));
3380 spec->autocfg.hp_outs = spec->autocfg.line_outs;
3381 memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
3382 sizeof(spec->autocfg.speaker_pins));
3383 spec->autocfg.line_outs = spec->autocfg.speaker_outs;
3384 memset(spec->autocfg.speaker_pins, 0,
3385 sizeof(spec->autocfg.speaker_pins));
3386 spec->autocfg.speaker_outs = 0;
3387 }
3388
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003389 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
3390
3391 if (err < 0)
3392 return err;
3393
3394 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
3395
3396 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003397 return err;
3398
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003399 if (spec->mono_nid > 0) {
3400 err = stac92xx_auto_create_mono_output_ctls(codec);
3401 if (err < 0)
3402 return err;
3403 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003404 if (spec->num_amps > 0) {
Matthew Ranostay89385032008-09-11 09:49:39 -04003405 err = stac92xx_auto_create_amp_output_ctls(codec);
3406 if (err < 0)
3407 return err;
3408 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003409 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02003410 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
3411 &spec->autocfg)) < 0)
3412 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003413 if (spec->num_muxes > 0) {
3414 err = stac92xx_auto_create_mux_input_ctls(codec);
3415 if (err < 0)
3416 return err;
3417 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02003418 if (spec->num_smuxes > 0) {
3419 err = stac92xx_auto_create_spdif_mux_ctls(codec);
3420 if (err < 0)
3421 return err;
3422 }
Matt Porter8b657272006-10-26 17:12:59 +02003423
Mattc7d4b2f2005-06-27 14:59:41 +02003424 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01003425 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02003426 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02003427
Takashi Iwai82bc9552006-03-21 11:24:42 +01003428 if (spec->autocfg.dig_out_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003429 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003430 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01003431 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02003432
3433 if (spec->kctl_alloc)
3434 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3435
3436 spec->input_mux = &spec->private_imux;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04003437 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02003438 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003439 spec->mono_mux = &spec->private_mono_mux;
Matthew Ranostay89385032008-09-11 09:49:39 -04003440 spec->amp_mux = &spec->private_amp_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02003441 return 1;
3442}
3443
Takashi Iwai82bc9552006-03-21 11:24:42 +01003444/* add playback controls for HP output */
3445static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
3446 struct auto_pin_cfg *cfg)
3447{
3448 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003449 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01003450 unsigned int wid_caps;
3451
3452 if (! pin)
3453 return 0;
3454
3455 wid_caps = get_wcaps(codec, pin);
Takashi Iwai505cb342006-03-27 12:51:52 +02003456 if (wid_caps & AC_WCAP_UNSOL_CAP)
Takashi Iwai82bc9552006-03-21 11:24:42 +01003457 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003458
3459 return 0;
3460}
3461
Richard Fish160ea0d2006-09-06 13:58:25 +02003462/* add playback controls for LFE output */
3463static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
3464 struct auto_pin_cfg *cfg)
3465{
3466 struct sigmatel_spec *spec = codec->spec;
3467 int err;
3468 hda_nid_t lfe_pin = 0x0;
3469 int i;
3470
3471 /*
3472 * search speaker outs and line outs for a mono speaker pin
3473 * with an amp. If one is found, add LFE controls
3474 * for it.
3475 */
3476 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
3477 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003478 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003479 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3480 if (wcaps == AC_WCAP_OUT_AMP)
3481 /* found a mono speaker with an amp, must be lfe */
3482 lfe_pin = pin;
3483 }
3484
3485 /* if speaker_outs is 0, then speakers may be in line_outs */
3486 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
3487 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
3488 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003489 unsigned int defcfg;
Harvey Harrison8b551782008-02-29 11:56:48 +01003490 defcfg = snd_hda_codec_read(codec, pin, 0,
Richard Fish160ea0d2006-09-06 13:58:25 +02003491 AC_VERB_GET_CONFIG_DEFAULT,
3492 0x00);
Harvey Harrison8b551782008-02-29 11:56:48 +01003493 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01003494 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02003495 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
3496 if (wcaps == AC_WCAP_OUT_AMP)
3497 /* found a mono speaker with an amp,
3498 must be lfe */
3499 lfe_pin = pin;
3500 }
3501 }
3502 }
3503
3504 if (lfe_pin) {
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003505 err = create_controls(spec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02003506 if (err < 0)
3507 return err;
3508 }
3509
3510 return 0;
3511}
3512
Mattc7d4b2f2005-06-27 14:59:41 +02003513static int stac9200_parse_auto_config(struct hda_codec *codec)
3514{
3515 struct sigmatel_spec *spec = codec->spec;
3516 int err;
3517
Kailang Yangdf694da2005-12-05 19:42:22 +01003518 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003519 return err;
3520
3521 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3522 return err;
3523
Takashi Iwai82bc9552006-03-21 11:24:42 +01003524 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
3525 return err;
3526
Richard Fish160ea0d2006-09-06 13:58:25 +02003527 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
3528 return err;
3529
Takashi Iwai82bc9552006-03-21 11:24:42 +01003530 if (spec->autocfg.dig_out_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003531 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003532 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02003533 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02003534
3535 if (spec->kctl_alloc)
3536 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3537
3538 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02003539 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02003540
3541 return 1;
3542}
3543
Sam Revitch62fe78e2006-05-10 15:09:17 +02003544/*
3545 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
3546 * funky external mute control using GPIO pins.
3547 */
3548
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003549static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003550 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02003551{
3552 unsigned int gpiostate, gpiomask, gpiodir;
3553
3554 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
3555 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003556 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003557
3558 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
3559 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003560 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003561
3562 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
3563 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003564 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02003565
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003566 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003567 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
3568
3569 snd_hda_codec_write(codec, codec->afg, 0,
3570 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003571 snd_hda_codec_read(codec, codec->afg, 0,
3572 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003573
3574 msleep(1);
3575
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01003576 snd_hda_codec_read(codec, codec->afg, 0,
3577 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02003578}
3579
Takashi Iwai314634b2006-09-21 11:56:18 +02003580static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3581 unsigned int event)
3582{
3583 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003584 snd_hda_codec_write_cache(codec, nid, 0,
3585 AC_VERB_SET_UNSOLICITED_ENABLE,
3586 (AC_USRSP_EN | event));
Takashi Iwai314634b2006-09-21 11:56:18 +02003587}
3588
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003589static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
3590{
3591 int i;
3592 for (i = 0; i < cfg->hp_outs; i++)
3593 if (cfg->hp_pins[i] == nid)
3594 return 1; /* nid is a HP-Out */
3595
3596 return 0; /* nid is not a HP-Out */
3597};
3598
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003599static void stac92xx_power_down(struct hda_codec *codec)
3600{
3601 struct sigmatel_spec *spec = codec->spec;
3602
3603 /* power down inactive DACs */
3604 hda_nid_t *dac;
3605 for (dac = spec->dac_list; *dac; dac++)
Matthew Ranostay44510892008-02-21 07:49:31 +01003606 if (!is_in_dac_nids(spec, *dac) &&
3607 spec->multiout.hp_nid != *dac)
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003608 snd_hda_codec_write_cache(codec, *dac, 0,
3609 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
3610}
3611
Mattc7d4b2f2005-06-27 14:59:41 +02003612static int stac92xx_init(struct hda_codec *codec)
3613{
3614 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003615 struct auto_pin_cfg *cfg = &spec->autocfg;
3616 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02003617
Mattc7d4b2f2005-06-27 14:59:41 +02003618 snd_hda_sequence_write(codec, spec->init);
3619
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003620 /* power down adcs initially */
3621 if (spec->powerdown_adcs)
3622 for (i = 0; i < spec->num_adcs; i++)
3623 snd_hda_codec_write_cache(codec,
3624 spec->adc_nids[i], 0,
3625 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003626 /* set up pins */
3627 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02003628 /* Enable unsolicited responses on the HP widget */
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003629 for (i = 0; i < cfg->hp_outs; i++)
Takashi Iwai314634b2006-09-21 11:56:18 +02003630 enable_pin_detect(codec, cfg->hp_pins[i],
3631 STAC_HP_EVENT);
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01003632 /* force to enable the first line-out; the others are set up
3633 * in unsol_event
3634 */
3635 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3636 AC_PINCTL_OUT_EN);
Takashi Iwaieb995a82006-09-21 14:28:21 +02003637 stac92xx_auto_init_hp_out(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003638 /* fake event to set up pins */
3639 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
3640 } else {
3641 stac92xx_auto_init_multi_out(codec);
3642 stac92xx_auto_init_hp_out(codec);
3643 }
3644 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaic960a032006-03-23 17:06:28 +01003645 hda_nid_t nid = cfg->input_pins[i];
3646 if (nid) {
Matthew Ranostayb9aea7152008-10-09 08:37:28 -04003647 unsigned int pinctl = snd_hda_codec_read(codec, nid,
3648 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3649 /* if PINCTL already set then skip */
3650 if (pinctl & AC_PINCAP_IN)
3651 continue;
3652 pinctl = AC_PINCTL_IN_EN;
Takashi Iwaic960a032006-03-23 17:06:28 +01003653 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3654 pinctl |= stac92xx_get_vref(codec, nid);
3655 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3656 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01003657 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003658 for (i = 0; i < spec->num_dmics; i++)
3659 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
3660 AC_PINCTL_IN_EN);
3661 for (i = 0; i < spec->num_pwrs; i++) {
3662 int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
3663 ? STAC_HP_EVENT : STAC_PWR_EVENT;
3664 int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
3665 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003666 int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
3667 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003668 def_conf = get_defcfg_connect(def_conf);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003669 /* outputs are only ports capable of power management
3670 * any attempts on powering down a input port cause the
3671 * referenced VREF to act quirky.
3672 */
3673 if (pinctl & AC_PINCTL_IN_EN)
3674 continue;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02003675 /* skip any ports that don't have jacks since presence
3676 * detection is useless */
3677 if (def_conf && def_conf != AC_JACK_PORT_FIXED)
Matthew Ranostaybce6c2b2008-02-29 12:07:43 +01003678 continue;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003679 enable_pin_detect(codec, spec->pwr_nids[i], event | i);
3680 codec->patch_ops.unsol_event(codec, (event | i) << 26);
3681 }
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003682 if (spec->dac_list)
3683 stac92xx_power_down(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01003684 if (cfg->dig_out_pin)
3685 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
3686 AC_PINCTL_OUT_EN);
3687 if (cfg->dig_in_pin)
3688 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
3689 AC_PINCTL_IN_EN);
3690
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003691 stac_gpio_set(codec, spec->gpio_mask,
3692 spec->gpio_dir, spec->gpio_data);
Sam Revitch62fe78e2006-05-10 15:09:17 +02003693
Mattc7d4b2f2005-06-27 14:59:41 +02003694 return 0;
3695}
3696
Matt2f2f4252005-04-13 14:45:30 +02003697static void stac92xx_free(struct hda_codec *codec)
3698{
Mattc7d4b2f2005-06-27 14:59:41 +02003699 struct sigmatel_spec *spec = codec->spec;
3700 int i;
3701
3702 if (! spec)
3703 return;
3704
3705 if (spec->kctl_alloc) {
3706 for (i = 0; i < spec->num_kctl_used; i++)
3707 kfree(spec->kctl_alloc[i].name);
3708 kfree(spec->kctl_alloc);
3709 }
3710
Richard Fish11b44bb2006-08-23 18:31:34 +02003711 if (spec->bios_pin_configs)
3712 kfree(spec->bios_pin_configs);
3713
Mattc7d4b2f2005-06-27 14:59:41 +02003714 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003715 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02003716}
3717
Matt4e550962005-07-04 17:51:39 +02003718static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
3719 unsigned int flag)
3720{
3721 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3722 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003723
Takashi Iwaif9acba42007-05-29 18:01:06 +02003724 if (pin_ctl & AC_PINCTL_IN_EN) {
3725 /*
3726 * we need to check the current set-up direction of
3727 * shared input pins since they can be switched via
3728 * "xxx as Output" mixer switch
3729 */
3730 struct sigmatel_spec *spec = codec->spec;
3731 struct auto_pin_cfg *cfg = &spec->autocfg;
3732 if ((nid == cfg->input_pins[AUTO_PIN_LINE] &&
3733 spec->line_switch) ||
3734 (nid == cfg->input_pins[AUTO_PIN_MIC] &&
3735 spec->mic_switch))
3736 return;
3737 }
3738
Steve Longerbeam7b0438992007-05-03 20:50:03 +02003739 /* if setting pin direction bits, clear the current
3740 direction bits first */
3741 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
3742 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
3743
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003744 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003745 AC_VERB_SET_PIN_WIDGET_CONTROL,
3746 pin_ctl | flag);
3747}
3748
3749static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
3750 unsigned int flag)
3751{
3752 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
3753 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003754 snd_hda_codec_write_cache(codec, nid, 0,
Matt4e550962005-07-04 17:51:39 +02003755 AC_VERB_SET_PIN_WIDGET_CONTROL,
3756 pin_ctl & ~flag);
3757}
3758
Jiang Zhe40c1d302007-11-12 13:05:16 +01003759static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02003760{
3761 if (!nid)
3762 return 0;
3763 if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
Jiang Zhe40c1d302007-11-12 13:05:16 +01003764 & (1 << 31)) {
3765 unsigned int pinctl;
3766 pinctl = snd_hda_codec_read(codec, nid, 0,
3767 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3768 if (pinctl & AC_PINCTL_IN_EN)
3769 return 0; /* mic- or line-input */
3770 else
3771 return 1; /* HP-output */
3772 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003773 return 0;
3774}
3775
3776static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
Matt4e550962005-07-04 17:51:39 +02003777{
3778 struct sigmatel_spec *spec = codec->spec;
3779 struct auto_pin_cfg *cfg = &spec->autocfg;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003780 int nid = cfg->hp_pins[cfg->hp_outs - 1];
Matt4e550962005-07-04 17:51:39 +02003781 int i, presence;
3782
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003783 presence = 0;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003784 if (spec->gpio_mute)
3785 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
3786 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
3787
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003788 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003789 if (presence)
3790 break;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003791 if (spec->hp_switch && cfg->hp_pins[i] == nid)
3792 break;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003793 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003794 }
Matt4e550962005-07-04 17:51:39 +02003795
3796 if (presence) {
3797 /* disable lineouts, enable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003798 if (spec->hp_switch)
3799 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003800 for (i = 0; i < cfg->line_outs; i++)
3801 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3802 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003803 for (i = 0; i < cfg->speaker_outs; i++)
3804 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
3805 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003806 if (spec->eapd_mask)
3807 stac_gpio_set(codec, spec->gpio_mask,
3808 spec->gpio_dir, spec->gpio_data &
3809 ~spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003810 } else {
3811 /* enable lineouts, disable hp */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003812 if (spec->hp_switch)
3813 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003814 for (i = 0; i < cfg->line_outs; i++)
3815 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3816 AC_PINCTL_OUT_EN);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003817 for (i = 0; i < cfg->speaker_outs; i++)
3818 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
3819 AC_PINCTL_OUT_EN);
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02003820 if (spec->eapd_mask)
3821 stac_gpio_set(codec, spec->gpio_mask,
3822 spec->gpio_dir, spec->gpio_data |
3823 spec->eapd_mask);
Matt4e550962005-07-04 17:51:39 +02003824 }
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003825 if (!spec->hp_switch && cfg->hp_outs > 1 && presence)
3826 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02003827}
3828
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003829static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3830{
3831 struct sigmatel_spec *spec = codec->spec;
3832 hda_nid_t nid = spec->pwr_nids[idx];
3833 int presence, val;
3834 val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
3835 & 0x000000ff;
3836 presence = get_hp_pin_presence(codec, nid);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003837
3838 /* several codecs have two power down bits */
3839 if (spec->pwr_mapping)
3840 idx = spec->pwr_mapping[idx];
3841 else
3842 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003843
3844 if (presence)
3845 val &= ~idx;
3846 else
3847 val |= idx;
3848
3849 /* power down unused output ports */
3850 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3851};
3852
Takashi Iwai314634b2006-09-21 11:56:18 +02003853static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3854{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003855 struct sigmatel_spec *spec = codec->spec;
3856 int idx = res >> 26 & 0x0f;
3857
Matthew Ranostay72474be2008-10-09 09:32:17 -04003858 switch ((res >> 26) & 0x70) {
Takashi Iwai314634b2006-09-21 11:56:18 +02003859 case STAC_HP_EVENT:
3860 stac92xx_hp_detect(codec, res);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003861 /* fallthru */
3862 case STAC_PWR_EVENT:
3863 if (spec->num_pwrs > 0)
3864 stac92xx_pin_sense(codec, idx);
Matthew Ranostay72474be2008-10-09 09:32:17 -04003865 break;
3866 case STAC_VREF_EVENT: {
3867 int data = snd_hda_codec_read(codec, codec->afg, 0,
3868 AC_VERB_GET_GPIO_DATA, 0);
3869 /* toggle VREF state based on GPIOx status */
3870 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
3871 !!(data & (1 << idx)));
3872 break;
3873 }
Takashi Iwai314634b2006-09-21 11:56:18 +02003874 }
3875}
3876
Takashi Iwaicb53c622007-08-10 17:21:45 +02003877#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003878static int stac92xx_resume(struct hda_codec *codec)
3879{
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003880 struct sigmatel_spec *spec = codec->spec;
3881
Richard Fish11b44bb2006-08-23 18:31:34 +02003882 stac92xx_set_config_regs(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003883 snd_hda_sequence_write(codec, spec->init);
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01003884 stac_gpio_set(codec, spec->gpio_mask,
3885 spec->gpio_dir, spec->gpio_data);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003886 snd_hda_codec_resume_amp(codec);
3887 snd_hda_codec_resume_cache(codec);
Matthew Ranostayb76c8502008-02-06 14:49:44 +01003888 /* power down inactive DACs */
3889 if (spec->dac_list)
3890 stac92xx_power_down(codec);
Takashi Iwaidc81bed2007-09-03 09:36:36 +02003891 /* invoke unsolicited event to reset the HP state */
3892 if (spec->hp_detect)
3893 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
Mattff6fdc32005-06-27 15:06:52 +02003894 return 0;
3895}
3896#endif
3897
Matt2f2f4252005-04-13 14:45:30 +02003898static struct hda_codec_ops stac92xx_patch_ops = {
3899 .build_controls = stac92xx_build_controls,
3900 .build_pcms = stac92xx_build_pcms,
3901 .init = stac92xx_init,
3902 .free = stac92xx_free,
Matt4e550962005-07-04 17:51:39 +02003903 .unsol_event = stac92xx_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003904#ifdef SND_HDA_NEEDS_RESUME
Mattff6fdc32005-06-27 15:06:52 +02003905 .resume = stac92xx_resume,
3906#endif
Matt2f2f4252005-04-13 14:45:30 +02003907};
3908
3909static int patch_stac9200(struct hda_codec *codec)
3910{
3911 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02003912 int err;
Matt2f2f4252005-04-13 14:45:30 +02003913
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003914 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02003915 if (spec == NULL)
3916 return -ENOMEM;
3917
3918 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003919 spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02003920 spec->pin_nids = stac9200_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003921 spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
3922 stac9200_models,
3923 stac9200_cfg_tbl);
Richard Fish11b44bb2006-08-23 18:31:34 +02003924 if (spec->board_config < 0) {
3925 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n");
3926 err = stac92xx_save_bios_config_regs(codec);
3927 if (err < 0) {
3928 stac92xx_free(codec);
3929 return err;
3930 }
3931 spec->pin_configs = spec->bios_pin_configs;
3932 } else {
Matt Porter403d1942005-11-29 15:00:51 +01003933 spec->pin_configs = stac9200_brd_tbl[spec->board_config];
3934 stac92xx_set_config_regs(codec);
3935 }
Matt2f2f4252005-04-13 14:45:30 +02003936
3937 spec->multiout.max_channels = 2;
3938 spec->multiout.num_dacs = 1;
3939 spec->multiout.dac_nids = stac9200_dac_nids;
3940 spec->adc_nids = stac9200_adc_nids;
3941 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02003942 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02003943 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003944 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01003945 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02003946
Tobin Davisbf277782008-02-03 20:31:47 +01003947 if (spec->board_config == STAC_9200_GATEWAY ||
3948 spec->board_config == STAC_9200_OQO)
Takashi Iwai1194b5b2007-10-10 10:04:26 +02003949 spec->init = stac9200_eapd_init;
3950 else
3951 spec->init = stac9200_core_init;
Matt2f2f4252005-04-13 14:45:30 +02003952 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02003953
Takashi Iwai117f2572008-03-18 09:53:23 +01003954 if (spec->board_config == STAC_9200_PANASONIC) {
3955 spec->gpio_mask = spec->gpio_dir = 0x09;
3956 spec->gpio_data = 0x00;
3957 }
3958
Mattc7d4b2f2005-06-27 14:59:41 +02003959 err = stac9200_parse_auto_config(codec);
3960 if (err < 0) {
3961 stac92xx_free(codec);
3962 return err;
3963 }
Matt2f2f4252005-04-13 14:45:30 +02003964
3965 codec->patch_ops = stac92xx_patch_ops;
3966
3967 return 0;
3968}
3969
Tobin Davis8e21c342007-01-08 11:04:17 +01003970static int patch_stac925x(struct hda_codec *codec)
3971{
3972 struct sigmatel_spec *spec;
3973 int err;
3974
3975 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3976 if (spec == NULL)
3977 return -ENOMEM;
3978
3979 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02003980 spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
Tobin Davis8e21c342007-01-08 11:04:17 +01003981 spec->pin_nids = stac925x_pin_nids;
3982 spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
3983 stac925x_models,
3984 stac925x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01003985 again:
Tobin Davis8e21c342007-01-08 11:04:17 +01003986 if (spec->board_config < 0) {
Tobin Davis2c11f952007-05-17 09:36:34 +02003987 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x,"
3988 "using BIOS defaults\n");
Tobin Davis8e21c342007-01-08 11:04:17 +01003989 err = stac92xx_save_bios_config_regs(codec);
3990 if (err < 0) {
3991 stac92xx_free(codec);
3992 return err;
3993 }
3994 spec->pin_configs = spec->bios_pin_configs;
3995 } else if (stac925x_brd_tbl[spec->board_config] != NULL){
3996 spec->pin_configs = stac925x_brd_tbl[spec->board_config];
3997 stac92xx_set_config_regs(codec);
3998 }
3999
4000 spec->multiout.max_channels = 2;
4001 spec->multiout.num_dacs = 1;
4002 spec->multiout.dac_nids = stac925x_dac_nids;
4003 spec->adc_nids = stac925x_adc_nids;
4004 spec->mux_nids = stac925x_mux_nids;
4005 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004006 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004007 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02004008 switch (codec->vendor_id) {
4009 case 0x83847632: /* STAC9202 */
4010 case 0x83847633: /* STAC9202D */
4011 case 0x83847636: /* STAC9251 */
4012 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02004013 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02004014 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004015 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
4016 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02004017 break;
4018 default:
4019 spec->num_dmics = 0;
4020 break;
4021 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004022
4023 spec->init = stac925x_core_init;
4024 spec->mixer = stac925x_mixer;
4025
4026 err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004027 if (!err) {
4028 if (spec->board_config < 0) {
4029 printk(KERN_WARNING "hda_codec: No auto-config is "
4030 "available, default to model=ref\n");
4031 spec->board_config = STAC_925x_REF;
4032 goto again;
4033 }
4034 err = -EINVAL;
4035 }
Tobin Davis8e21c342007-01-08 11:04:17 +01004036 if (err < 0) {
4037 stac92xx_free(codec);
4038 return err;
4039 }
4040
4041 codec->patch_ops = stac92xx_patch_ops;
4042
4043 return 0;
4044}
4045
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004046static struct hda_input_mux stac92hd73xx_dmux = {
4047 .num_items = 4,
4048 .items = {
4049 { "Analog Inputs", 0x0b },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004050 { "Digital Mic 1", 0x09 },
4051 { "Digital Mic 2", 0x0a },
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004052 { "CD", 0x08 },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004053 }
4054};
4055
4056static int patch_stac92hd73xx(struct hda_codec *codec)
4057{
4058 struct sigmatel_spec *spec;
4059 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
4060 int err = 0;
4061
4062 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4063 if (spec == NULL)
4064 return -ENOMEM;
4065
4066 codec->spec = spec;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02004067 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004068 spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
4069 spec->pin_nids = stac92hd73xx_pin_nids;
4070 spec->board_config = snd_hda_check_board_config(codec,
4071 STAC_92HD73XX_MODELS,
4072 stac92hd73xx_models,
4073 stac92hd73xx_cfg_tbl);
4074again:
4075 if (spec->board_config < 0) {
4076 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4077 " STAC92HD73XX, using BIOS defaults\n");
4078 err = stac92xx_save_bios_config_regs(codec);
4079 if (err < 0) {
4080 stac92xx_free(codec);
4081 return err;
4082 }
4083 spec->pin_configs = spec->bios_pin_configs;
4084 } else {
4085 spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
4086 stac92xx_set_config_regs(codec);
4087 }
4088
4089 spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
4090 conn, STAC92HD73_DAC_COUNT + 2) - 1;
4091
4092 if (spec->multiout.num_dacs < 0) {
4093 printk(KERN_WARNING "hda_codec: Could not determine "
4094 "number of channels defaulting to DAC count\n");
4095 spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
4096 }
4097
4098 switch (spec->multiout.num_dacs) {
4099 case 0x3: /* 6 Channel */
4100 spec->mixer = stac92hd73xx_6ch_mixer;
4101 spec->init = stac92hd73xx_6ch_core_init;
4102 break;
4103 case 0x4: /* 8 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004104 spec->mixer = stac92hd73xx_8ch_mixer;
4105 spec->init = stac92hd73xx_8ch_core_init;
4106 break;
4107 case 0x5: /* 10 Channel */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004108 spec->mixer = stac92hd73xx_10ch_mixer;
4109 spec->init = stac92hd73xx_10ch_core_init;
4110 };
4111
4112 spec->multiout.dac_nids = stac92hd73xx_dac_nids;
4113 spec->aloopback_mask = 0x01;
4114 spec->aloopback_shift = 8;
4115
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004116 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004117 spec->mux_nids = stac92hd73xx_mux_nids;
4118 spec->adc_nids = stac92hd73xx_adc_nids;
4119 spec->dmic_nids = stac92hd73xx_dmic_nids;
4120 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004121 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostay89385032008-09-11 09:49:39 -04004122 spec->amp_nids = stac92hd73xx_amp_nids;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004123 spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004124
4125 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
4126 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01004127 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004128 memcpy(&spec->private_dimux, &stac92hd73xx_dmux,
4129 sizeof(stac92hd73xx_dmux));
4130
Matthew Ranostaya7662642008-02-21 07:51:14 +01004131 switch (spec->board_config) {
4132 case STAC_DELL_M6:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004133 spec->init = dell_eq_core_init;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004134 spec->num_smuxes = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004135 spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER];
4136 spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP];
4137 spec->num_amps = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004138 switch (codec->subsystem_id) {
4139 case 0x1028025e: /* Analog Mics */
4140 case 0x1028025f:
4141 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4142 spec->num_dmics = 0;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004143 spec->private_dimux.num_items = 1;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004144 break;
Matthew Ranostayd654a662008-03-14 08:46:51 +01004145 case 0x10280271: /* Digital Mics */
Matthew Ranostaya7662642008-02-21 07:51:14 +01004146 case 0x10280272:
Matthew Ranostayd654a662008-03-14 08:46:51 +01004147 spec->init = dell_m6_core_init;
4148 /* fall-through */
4149 case 0x10280254:
4150 case 0x10280255:
Matthew Ranostaya7662642008-02-21 07:51:14 +01004151 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4152 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004153 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004154 break;
4155 case 0x10280256: /* Both */
4156 case 0x10280057:
4157 stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
4158 stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
4159 spec->num_dmics = 1;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004160 spec->private_dimux.num_items = 2;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004161 break;
4162 }
4163 break;
4164 default:
4165 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004166 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostaya7662642008-02-21 07:51:14 +01004167 }
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004168 if (spec->board_config > STAC_92HD73XX_REF) {
4169 /* GPIO0 High = Enable EAPD */
4170 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
4171 spec->gpio_data = 0x01;
4172 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004173 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostaya7662642008-02-21 07:51:14 +01004174
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004175 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
4176 spec->pwr_nids = stac92hd73xx_pwr_nids;
4177
Matthew Ranostayd9737752008-09-07 12:03:41 +02004178 err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004179
4180 if (!err) {
4181 if (spec->board_config < 0) {
4182 printk(KERN_WARNING "hda_codec: No auto-config is "
4183 "available, default to model=ref\n");
4184 spec->board_config = STAC_92HD73XX_REF;
4185 goto again;
4186 }
4187 err = -EINVAL;
4188 }
4189
4190 if (err < 0) {
4191 stac92xx_free(codec);
4192 return err;
4193 }
4194
4195 codec->patch_ops = stac92xx_patch_ops;
4196
4197 return 0;
4198}
4199
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004200static struct hda_input_mux stac92hd83xxx_dmux = {
4201 .num_items = 3,
4202 .items = {
4203 { "Analog Inputs", 0x03 },
4204 { "Digital Mic 1", 0x04 },
4205 { "Digital Mic 2", 0x05 },
4206 }
4207};
4208
4209static int patch_stac92hd83xxx(struct hda_codec *codec)
4210{
4211 struct sigmatel_spec *spec;
4212 int err;
4213
4214 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4215 if (spec == NULL)
4216 return -ENOMEM;
4217
4218 codec->spec = spec;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004219 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004220 spec->mono_nid = 0x19;
4221 spec->digbeep_nid = 0x21;
4222 spec->dmic_nids = stac92hd83xxx_dmic_nids;
4223 spec->dmux_nids = stac92hd83xxx_dmux_nids;
4224 spec->adc_nids = stac92hd83xxx_adc_nids;
4225 spec->pwr_nids = stac92hd83xxx_pwr_nids;
4226 spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
4227 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
4228 spec->multiout.dac_nids = stac92hd83xxx_dac_nids;
4229
4230 spec->init = stac92hd83xxx_core_init;
4231 switch (codec->vendor_id) {
4232 case 0x111d7605:
4233 spec->multiout.num_dacs = STAC92HD81_DAC_COUNT;
4234 break;
4235 default:
4236 spec->num_pwrs--;
4237 spec->init++; /* switch to config #2 */
4238 spec->multiout.num_dacs = STAC92HD83_DAC_COUNT;
4239 }
4240
4241 spec->mixer = stac92hd83xxx_mixer;
4242 spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
4243 spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids);
4244 spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
4245 spec->num_dmics = STAC92HD83XXX_NUM_DMICS;
4246 spec->dinput_mux = &stac92hd83xxx_dmux;
4247 spec->pin_nids = stac92hd83xxx_pin_nids;
4248 spec->board_config = snd_hda_check_board_config(codec,
4249 STAC_92HD83XXX_MODELS,
4250 stac92hd83xxx_models,
4251 stac92hd83xxx_cfg_tbl);
4252again:
4253 if (spec->board_config < 0) {
4254 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4255 " STAC92HD83XXX, using BIOS defaults\n");
4256 err = stac92xx_save_bios_config_regs(codec);
4257 if (err < 0) {
4258 stac92xx_free(codec);
4259 return err;
4260 }
4261 spec->pin_configs = spec->bios_pin_configs;
4262 } else {
4263 spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config];
4264 stac92xx_set_config_regs(codec);
4265 }
4266
4267 err = stac92xx_parse_auto_config(codec, 0x1d, 0);
4268 if (!err) {
4269 if (spec->board_config < 0) {
4270 printk(KERN_WARNING "hda_codec: No auto-config is "
4271 "available, default to model=ref\n");
4272 spec->board_config = STAC_92HD83XXX_REF;
4273 goto again;
4274 }
4275 err = -EINVAL;
4276 }
4277
4278 if (err < 0) {
4279 stac92xx_free(codec);
4280 return err;
4281 }
4282
4283 codec->patch_ops = stac92xx_patch_ops;
4284
4285 return 0;
4286}
4287
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004288#ifdef SND_HDA_NEEDS_RESUME
4289static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr)
4290{
4291 struct sigmatel_spec *spec = codec->spec;
4292 int i;
4293 snd_hda_codec_write_cache(codec, codec->afg, 0,
4294 AC_VERB_SET_POWER_STATE, pwr);
4295
4296 msleep(1);
4297 for (i = 0; i < spec->num_adcs; i++) {
4298 snd_hda_codec_write_cache(codec,
4299 spec->adc_nids[i], 0,
4300 AC_VERB_SET_POWER_STATE, pwr);
4301 }
4302};
4303
4304static int stac92hd71xx_resume(struct hda_codec *codec)
4305{
4306 stac92hd71xx_set_power_state(codec, AC_PWRST_D0);
4307 return stac92xx_resume(codec);
4308}
4309
4310static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state)
4311{
4312 stac92hd71xx_set_power_state(codec, AC_PWRST_D3);
4313 return 0;
4314};
4315
4316#endif
4317
4318static struct hda_codec_ops stac92hd71bxx_patch_ops = {
4319 .build_controls = stac92xx_build_controls,
4320 .build_pcms = stac92xx_build_pcms,
4321 .init = stac92xx_init,
4322 .free = stac92xx_free,
4323 .unsol_event = stac92xx_unsol_event,
4324#ifdef SND_HDA_NEEDS_RESUME
4325 .resume = stac92hd71xx_resume,
4326 .suspend = stac92hd71xx_suspend,
4327#endif
4328};
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004329
Matthew Ranostaye035b842007-11-06 11:53:55 +01004330static int patch_stac92hd71bxx(struct hda_codec *codec)
4331{
4332 struct sigmatel_spec *spec;
4333 int err = 0;
4334
4335 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4336 if (spec == NULL)
4337 return -ENOMEM;
4338
4339 codec->spec = spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004340 codec->patch_ops = stac92xx_patch_ops;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004341 spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004342 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004343 spec->pin_nids = stac92hd71bxx_pin_nids;
4344 spec->board_config = snd_hda_check_board_config(codec,
4345 STAC_92HD71BXX_MODELS,
4346 stac92hd71bxx_models,
4347 stac92hd71bxx_cfg_tbl);
4348again:
4349 if (spec->board_config < 0) {
4350 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4351 " STAC92HD71BXX, using BIOS defaults\n");
4352 err = stac92xx_save_bios_config_regs(codec);
4353 if (err < 0) {
4354 stac92xx_free(codec);
4355 return err;
4356 }
4357 spec->pin_configs = spec->bios_pin_configs;
4358 } else {
4359 spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
4360 stac92xx_set_config_regs(codec);
4361 }
4362
Matthew Ranostay541eee82007-12-14 12:08:04 +01004363 switch (codec->vendor_id) {
4364 case 0x111d76b6: /* 4 Port without Analog Mixer */
4365 case 0x111d76b7:
4366 case 0x111d76b4: /* 6 Port without Analog Mixer */
4367 case 0x111d76b5:
4368 spec->mixer = stac92hd71bxx_mixer;
4369 spec->init = stac92hd71bxx_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004370 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004371 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004372 case 0x111d7608: /* 5 Port with Analog Mixer */
Matthew Ranostay72474be2008-10-09 09:32:17 -04004373 switch (codec->subsystem_id) {
4374 case 0x103c361a:
4375 /* Enable VREF power saving on GPIO1 detect */
4376 snd_hda_codec_write(codec, codec->afg, 0,
4377 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4378 snd_hda_codec_write_cache(codec, codec->afg, 0,
4379 AC_VERB_SET_UNSOLICITED_ENABLE,
4380 (AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
4381 spec->gpio_mask |= 0x02;
4382 break;
4383 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004384 if ((codec->revision_id & 0xf) == 0 ||
4385 (codec->revision_id & 0xf) == 1) {
4386#ifdef SND_HDA_NEEDS_RESUME
4387 codec->patch_ops = stac92hd71bxx_patch_ops;
4388#endif
4389 spec->stream_delay = 40; /* 40 milliseconds */
4390 }
4391
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004392 /* no output amps */
4393 spec->num_pwrs = 0;
4394 spec->mixer = stac92hd71bxx_analog_mixer;
4395
4396 /* disable VSW */
4397 spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
4398 stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
4399 break;
4400 case 0x111d7603: /* 6 Port with Analog Mixer */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004401 if ((codec->revision_id & 0xf) == 1) {
4402#ifdef SND_HDA_NEEDS_RESUME
4403 codec->patch_ops = stac92hd71bxx_patch_ops;
4404#endif
4405 spec->stream_delay = 40; /* 40 milliseconds */
4406 }
4407
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004408 /* no output amps */
4409 spec->num_pwrs = 0;
4410 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01004411 default:
4412 spec->mixer = stac92hd71bxx_analog_mixer;
4413 spec->init = stac92hd71bxx_analog_core_init;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04004414 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Matthew Ranostay541eee82007-12-14 12:08:04 +01004415 }
4416
4417 spec->aloopback_mask = 0x20;
4418 spec->aloopback_shift = 0;
4419
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004420 if (spec->board_config > STAC_92HD71BXX_REF) {
4421 /* GPIO0 = EAPD */
4422 spec->gpio_mask = 0x01;
4423 spec->gpio_dir = 0x01;
4424 spec->gpio_data = 0x01;
4425 }
Matthew Ranostaye035b842007-11-06 11:53:55 +01004426
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004427 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004428 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004429 spec->mux_nids = stac92hd71bxx_mux_nids;
4430 spec->adc_nids = stac92hd71bxx_adc_nids;
4431 spec->dmic_nids = stac92hd71bxx_dmic_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004432 spec->dmux_nids = stac92hd71bxx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004433 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02004434 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004435
4436 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
4437 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01004438
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004439 switch (spec->board_config) {
4440 case STAC_HP_M4:
4441 spec->num_dmics = 0;
Matthew Ranostayb9aea7152008-10-09 08:37:28 -04004442 spec->num_smuxes = 0;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004443 spec->num_dmuxes = 0;
4444
4445 /* enable internal microphone */
Matthew Ranostayb9aea7152008-10-09 08:37:28 -04004446 stac92xx_set_config_reg(codec, 0x0e, 0x01813040);
4447 stac92xx_auto_set_pinctl(codec, 0x0e,
4448 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay6a14f582008-09-12 12:02:30 -04004449 break;
4450 default:
4451 spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
4452 spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids);
4453 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
4454 };
4455
Takashi Iwaiaea7bb02008-02-25 18:26:41 +01004456 spec->multiout.num_dacs = 1;
Matthew Ranostaye035b842007-11-06 11:53:55 +01004457 spec->multiout.hp_nid = 0x11;
4458 spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
4459
4460 err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
4461 if (!err) {
4462 if (spec->board_config < 0) {
4463 printk(KERN_WARNING "hda_codec: No auto-config is "
4464 "available, default to model=ref\n");
4465 spec->board_config = STAC_92HD71BXX_REF;
4466 goto again;
4467 }
4468 err = -EINVAL;
4469 }
4470
4471 if (err < 0) {
4472 stac92xx_free(codec);
4473 return err;
4474 }
4475
Matthew Ranostaye035b842007-11-06 11:53:55 +01004476 return 0;
4477};
4478
Matt2f2f4252005-04-13 14:45:30 +02004479static int patch_stac922x(struct hda_codec *codec)
4480{
4481 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004482 int err;
Matt2f2f4252005-04-13 14:45:30 +02004483
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004484 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Matt2f2f4252005-04-13 14:45:30 +02004485 if (spec == NULL)
4486 return -ENOMEM;
4487
4488 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004489 spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004490 spec->pin_nids = stac922x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004491 spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
4492 stac922x_models,
4493 stac922x_cfg_tbl);
Nicolas Boichat536319a2008-07-21 22:18:01 +08004494 if (spec->board_config == STAC_INTEL_MAC_AUTO) {
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004495 spec->gpio_mask = spec->gpio_dir = 0x03;
4496 spec->gpio_data = 0x03;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004497 /* Intel Macs have all same PCI SSID, so we need to check
4498 * codec SSID to distinguish the exact models
4499 */
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004500 printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004501 switch (codec->subsystem_id) {
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004502
4503 case 0x106b0800:
4504 spec->board_config = STAC_INTEL_MAC_V1;
Abhijit Bhopatkarc45e20e2007-04-17 11:57:16 +02004505 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004506 case 0x106b0600:
4507 case 0x106b0700:
4508 spec->board_config = STAC_INTEL_MAC_V2;
Nicolas Boichat6f0778d2007-03-15 12:38:15 +01004509 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004510 case 0x106b0e00:
4511 case 0x106b0f00:
4512 case 0x106b1600:
4513 case 0x106b1700:
4514 case 0x106b0200:
4515 case 0x106b1e00:
4516 spec->board_config = STAC_INTEL_MAC_V3;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004517 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004518 case 0x106b1a00:
4519 case 0x00000100:
4520 spec->board_config = STAC_INTEL_MAC_V4;
Sylvain FORETf16928f2007-04-27 14:22:36 +02004521 break;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02004522 case 0x106b0a00:
4523 case 0x106b2200:
4524 spec->board_config = STAC_INTEL_MAC_V5;
Takashi Iwai0dae0f82007-05-21 12:41:29 +02004525 break;
Nicolas Boichat536319a2008-07-21 22:18:01 +08004526 default:
4527 spec->board_config = STAC_INTEL_MAC_V3;
4528 break;
Takashi Iwai3fc24d82007-02-16 13:27:18 +01004529 }
4530 }
4531
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004532 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004533 if (spec->board_config < 0) {
4534 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, "
4535 "using BIOS defaults\n");
4536 err = stac92xx_save_bios_config_regs(codec);
4537 if (err < 0) {
4538 stac92xx_free(codec);
4539 return err;
4540 }
4541 spec->pin_configs = spec->bios_pin_configs;
4542 } else if (stac922x_brd_tbl[spec->board_config] != NULL) {
Matt Porter403d1942005-11-29 15:00:51 +01004543 spec->pin_configs = stac922x_brd_tbl[spec->board_config];
4544 stac92xx_set_config_regs(codec);
4545 }
Matt2f2f4252005-04-13 14:45:30 +02004546
Matt2f2f4252005-04-13 14:45:30 +02004547 spec->adc_nids = stac922x_adc_nids;
4548 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004549 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004550 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004551 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004552 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02004553
4554 spec->init = stac922x_core_init;
Matt2f2f4252005-04-13 14:45:30 +02004555 spec->mixer = stac922x_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02004556
4557 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02004558
Matt Porter3cc08dc2006-01-23 15:27:49 +01004559 err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004560 if (!err) {
4561 if (spec->board_config < 0) {
4562 printk(KERN_WARNING "hda_codec: No auto-config is "
4563 "available, default to model=ref\n");
4564 spec->board_config = STAC_D945_REF;
4565 goto again;
4566 }
4567 err = -EINVAL;
4568 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004569 if (err < 0) {
4570 stac92xx_free(codec);
4571 return err;
4572 }
4573
4574 codec->patch_ops = stac92xx_patch_ops;
4575
Takashi Iwai807a46362007-05-29 19:01:37 +02004576 /* Fix Mux capture level; max to 2 */
4577 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
4578 (0 << AC_AMPCAP_OFFSET_SHIFT) |
4579 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4580 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4581 (0 << AC_AMPCAP_MUTE_SHIFT));
4582
Matt Porter3cc08dc2006-01-23 15:27:49 +01004583 return 0;
4584}
4585
4586static int patch_stac927x(struct hda_codec *codec)
4587{
4588 struct sigmatel_spec *spec;
4589 int err;
4590
4591 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4592 if (spec == NULL)
4593 return -ENOMEM;
4594
4595 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004596 spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004597 spec->pin_nids = stac927x_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004598 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
4599 stac927x_models,
4600 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004601 again:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004602 if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
4603 if (spec->board_config < 0)
4604 snd_printdd(KERN_INFO "hda_codec: Unknown model for"
4605 "STAC927x, using BIOS defaults\n");
Richard Fish11b44bb2006-08-23 18:31:34 +02004606 err = stac92xx_save_bios_config_regs(codec);
4607 if (err < 0) {
4608 stac92xx_free(codec);
4609 return err;
4610 }
4611 spec->pin_configs = spec->bios_pin_configs;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004612 } else {
Matt Porter3cc08dc2006-01-23 15:27:49 +01004613 spec->pin_configs = stac927x_brd_tbl[spec->board_config];
4614 stac92xx_set_config_regs(codec);
4615 }
4616
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004617 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004618 spec->adc_nids = stac927x_adc_nids;
4619 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
4620 spec->mux_nids = stac927x_mux_nids;
4621 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004622 spec->smux_nids = stac927x_smux_nids;
4623 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04004624 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004625 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004626 spec->multiout.dac_nids = spec->dac_nids;
4627
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004628 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02004629 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004630 case STAC_D965_5ST:
4631 /* GPIO0 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004632 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x01;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004633 spec->gpio_data = 0x01;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004634 spec->num_dmics = 0;
4635
Tobin Davis93ed1502006-09-01 21:03:12 +02004636 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004637 spec->mixer = stac927x_mixer;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004638 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004639 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02004640 switch (codec->subsystem_id) {
4641 case 0x10280209:
4642 case 0x1028022e:
4643 /* correct the device field to SPDIF out */
4644 stac92xx_set_config_reg(codec, 0x21, 0x01442070);
4645 break;
4646 };
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01004647 /* configure the analog microphone on some laptops */
4648 stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01004649 /* correct the front output jack as a hp out */
Matthew Ranostay7989fba2008-02-21 07:50:12 +01004650 stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01004651 /* correct the front input jack as a mic */
4652 stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
4653 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004654 case STAC_DELL_3ST:
4655 /* GPIO2 High = Enable EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004656 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004657 spec->gpio_data = 0x04;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004658 spec->dmic_nids = stac927x_dmic_nids;
4659 spec->num_dmics = STAC927X_NUM_DMICS;
4660
Tobin Davis93ed1502006-09-01 21:03:12 +02004661 spec->init = d965_core_init;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004662 spec->mixer = stac927x_mixer;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004663 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004664 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004665 break;
4666 default:
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004667 if (spec->board_config > STAC_D965_REF) {
4668 /* GPIO0 High = Enable EAPD */
4669 spec->eapd_mask = spec->gpio_mask = 0x01;
4670 spec->gpio_dir = spec->gpio_data = 0x01;
4671 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004672 spec->num_dmics = 0;
4673
Tobin Davis81d3dbd2006-08-22 19:44:45 +02004674 spec->init = stac927x_core_init;
4675 spec->mixer = stac927x_mixer;
4676 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01004677
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004678 spec->num_pwrs = 0;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004679 spec->aloopback_mask = 0x40;
4680 spec->aloopback_shift = 0;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01004681
Matt Porter3cc08dc2006-01-23 15:27:49 +01004682 err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004683 if (!err) {
4684 if (spec->board_config < 0) {
4685 printk(KERN_WARNING "hda_codec: No auto-config is "
4686 "available, default to model=ref\n");
4687 spec->board_config = STAC_D965_REF;
4688 goto again;
4689 }
4690 err = -EINVAL;
4691 }
Mattc7d4b2f2005-06-27 14:59:41 +02004692 if (err < 0) {
4693 stac92xx_free(codec);
4694 return err;
4695 }
Matt2f2f4252005-04-13 14:45:30 +02004696
4697 codec->patch_ops = stac92xx_patch_ops;
4698
Takashi Iwai52987652008-01-16 16:09:47 +01004699 /*
4700 * !!FIXME!!
4701 * The STAC927x seem to require fairly long delays for certain
4702 * command sequences. With too short delays (even if the answer
4703 * is set to RIRB properly), it results in the silence output
4704 * on some hardwares like Dell.
4705 *
4706 * The below flag enables the longer delay (see get_response
4707 * in hda_intel.c).
4708 */
4709 codec->bus->needs_damn_long_delay = 1;
4710
Matt2f2f4252005-04-13 14:45:30 +02004711 return 0;
4712}
4713
Matt Porterf3302a52006-07-31 12:49:34 +02004714static int patch_stac9205(struct hda_codec *codec)
4715{
4716 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02004717 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02004718
4719 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4720 if (spec == NULL)
4721 return -ENOMEM;
4722
4723 codec->spec = spec;
Takashi Iwaia4eed132007-07-06 18:17:04 +02004724 spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
Richard Fish11b44bb2006-08-23 18:31:34 +02004725 spec->pin_nids = stac9205_pin_nids;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004726 spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
4727 stac9205_models,
4728 stac9205_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004729 again:
Richard Fish11b44bb2006-08-23 18:31:34 +02004730 if (spec->board_config < 0) {
4731 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n");
4732 err = stac92xx_save_bios_config_regs(codec);
4733 if (err < 0) {
4734 stac92xx_free(codec);
4735 return err;
4736 }
4737 spec->pin_configs = spec->bios_pin_configs;
4738 } else {
Matt Porterf3302a52006-07-31 12:49:34 +02004739 spec->pin_configs = stac9205_brd_tbl[spec->board_config];
4740 stac92xx_set_config_regs(codec);
4741 }
4742
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004743 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02004744 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02004745 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02004746 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01004747 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004748 spec->smux_nids = stac9205_smux_nids;
4749 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02004750 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02004751 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004752 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01004753 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004754 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004755
4756 spec->init = stac9205_core_init;
4757 spec->mixer = stac9205_mixer;
4758
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01004759 spec->aloopback_mask = 0x40;
4760 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02004761 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02004762
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004763 switch (spec->board_config){
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004764 case STAC_9205_DELL_M43:
Matthew Ranostay87d48362007-07-17 11:52:24 +02004765 /* Enable SPDIF in/out */
4766 stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
4767 stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
Matt Porter33382402006-12-18 13:17:28 +01004768
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004769 /* Enable unsol response for GPIO4/Dock HP connection */
4770 snd_hda_codec_write(codec, codec->afg, 0,
4771 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4772 snd_hda_codec_write_cache(codec, codec->afg, 0,
4773 AC_VERB_SET_UNSOLICITED_ENABLE,
4774 (AC_USRSP_EN | STAC_HP_EVENT));
4775
4776 spec->gpio_dir = 0x0b;
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004777 spec->eapd_mask = 0x01;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004778 spec->gpio_mask = 0x1b;
4779 spec->gpio_mute = 0x10;
Matthew Ranostaye2e7d622008-01-24 15:32:15 +01004780 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004781 * GPIO3 Low = DRM
Matthew Ranostay87d48362007-07-17 11:52:24 +02004782 */
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004783 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004784 break;
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04004785 case STAC_9205_REF:
4786 /* SPDIF-In enabled */
4787 break;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004788 default:
4789 /* GPIO0 High = EAPD */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +02004790 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
Matthew Ranostay4fe5195c2008-01-29 15:28:44 +01004791 spec->gpio_data = 0x01;
Tobin Davisae0a8ed2007-08-13 15:50:29 +02004792 break;
4793 }
Matthew Ranostay87d48362007-07-17 11:52:24 +02004794
Matt Porterf3302a52006-07-31 12:49:34 +02004795 err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01004796 if (!err) {
4797 if (spec->board_config < 0) {
4798 printk(KERN_WARNING "hda_codec: No auto-config is "
4799 "available, default to model=ref\n");
4800 spec->board_config = STAC_9205_REF;
4801 goto again;
4802 }
4803 err = -EINVAL;
4804 }
Matt Porterf3302a52006-07-31 12:49:34 +02004805 if (err < 0) {
4806 stac92xx_free(codec);
4807 return err;
4808 }
4809
4810 codec->patch_ops = stac92xx_patch_ops;
4811
4812 return 0;
4813}
4814
Matt2f2f4252005-04-13 14:45:30 +02004815/*
Guillaume Munch6d859062006-08-22 17:15:47 +02004816 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01004817 */
4818
Guillaume Munch99ccc562006-08-16 19:35:12 +02004819/* static config for Sony VAIO FE550G and Sony VAIO AR */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004820static hda_nid_t vaio_dacs[] = { 0x2 };
4821#define VAIO_HP_DAC 0x5
4822static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
4823static hda_nid_t vaio_mux_nids[] = { 0x15 };
4824
4825static struct hda_input_mux vaio_mux = {
Takashi Iwaia3a2f422007-10-11 11:21:21 +02004826 .num_items = 3,
Takashi Iwaidb064e52006-03-16 16:04:58 +01004827 .items = {
Takashi Iwaid7737812006-04-25 13:05:43 +02004828 /* { "HP", 0x0 }, */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004829 { "Mic Jack", 0x1 },
4830 { "Internal Mic", 0x2 },
Takashi Iwaidb064e52006-03-16 16:04:58 +01004831 { "PCM", 0x3 },
4832 }
4833};
4834
4835static struct hda_verb vaio_init[] = {
4836 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004837 {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT},
Takashi Iwaidb064e52006-03-16 16:04:58 +01004838 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4839 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4840 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4841 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004842 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01004843 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4844 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4845 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4846 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4847 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4848 {}
4849};
4850
Guillaume Munch6d859062006-08-22 17:15:47 +02004851static struct hda_verb vaio_ar_init[] = {
4852 {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
4853 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
4854 {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
4855 {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
4856/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
4857 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
Takashi Iwai1624cb92007-07-05 13:10:51 +02004858 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Guillaume Munch6d859062006-08-22 17:15:47 +02004859 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
4860 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
4861/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
4862 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
4863 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
4864 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
4865 {}
4866};
4867
Takashi Iwaidb064e52006-03-16 16:04:58 +01004868/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004869static struct hda_bind_ctls vaio_bind_master_vol = {
4870 .ops = &snd_hda_bind_vol,
4871 .values = {
4872 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4873 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4874 0
4875 },
4876};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004877
4878/* bind volumes of both NID 0x02 and 0x05 */
Takashi Iwaicca3b372007-08-10 17:12:15 +02004879static struct hda_bind_ctls vaio_bind_master_sw = {
4880 .ops = &snd_hda_bind_sw,
4881 .values = {
4882 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
4883 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
4884 0,
4885 },
4886};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004887
4888static struct snd_kcontrol_new vaio_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004889 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4890 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004891 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4892 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4893 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4894 {
4895 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4896 .name = "Capture Source",
4897 .count = 1,
4898 .info = stac92xx_mux_enum_info,
4899 .get = stac92xx_mux_enum_get,
4900 .put = stac92xx_mux_enum_put,
4901 },
4902 {}
4903};
4904
Guillaume Munch6d859062006-08-22 17:15:47 +02004905static struct snd_kcontrol_new vaio_ar_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02004906 HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol),
4907 HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw),
Guillaume Munch6d859062006-08-22 17:15:47 +02004908 /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
4909 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
4910 HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
4911 /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
4912 HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/
4913 {
4914 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4915 .name = "Capture Source",
4916 .count = 1,
4917 .info = stac92xx_mux_enum_info,
4918 .get = stac92xx_mux_enum_get,
4919 .put = stac92xx_mux_enum_put,
4920 },
4921 {}
4922};
4923
4924static struct hda_codec_ops stac9872_patch_ops = {
Takashi Iwaidb064e52006-03-16 16:04:58 +01004925 .build_controls = stac92xx_build_controls,
4926 .build_pcms = stac92xx_build_pcms,
4927 .init = stac92xx_init,
4928 .free = stac92xx_free,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004929#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaidb064e52006-03-16 16:04:58 +01004930 .resume = stac92xx_resume,
4931#endif
4932};
4933
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004934static int stac9872_vaio_init(struct hda_codec *codec)
4935{
4936 int err;
4937
4938 err = stac92xx_init(codec);
4939 if (err < 0)
4940 return err;
4941 if (codec->patch_ops.unsol_event)
4942 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
4943 return 0;
4944}
4945
4946static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
4947{
Jiang Zhe40c1d302007-11-12 13:05:16 +01004948 if (get_hp_pin_presence(codec, 0x0a)) {
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02004949 stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4950 stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4951 } else {
4952 stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
4953 stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
4954 }
4955}
4956
4957static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res)
4958{
4959 switch (res >> 26) {
4960 case STAC_HP_EVENT:
4961 stac9872_vaio_hp_detect(codec, res);
4962 break;
4963 }
4964}
4965
4966static struct hda_codec_ops stac9872_vaio_patch_ops = {
4967 .build_controls = stac92xx_build_controls,
4968 .build_pcms = stac92xx_build_pcms,
4969 .init = stac9872_vaio_init,
4970 .free = stac92xx_free,
4971 .unsol_event = stac9872_vaio_unsol_event,
4972#ifdef CONFIG_PM
4973 .resume = stac92xx_resume,
4974#endif
4975};
4976
Guillaume Munch6d859062006-08-22 17:15:47 +02004977enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
4978 CXD9872RD_VAIO,
4979 /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
4980 STAC9872AK_VAIO,
4981 /* Unknown. id=0x83847661 and subsys=0x104D1200. */
4982 STAC9872K_VAIO,
4983 /* AR Series. id=0x83847664 and subsys=104D1300 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004984 CXD9872AKD_VAIO,
4985 STAC_9872_MODELS,
4986};
Takashi Iwaidb064e52006-03-16 16:04:58 +01004987
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004988static const char *stac9872_models[STAC_9872_MODELS] = {
4989 [CXD9872RD_VAIO] = "vaio",
4990 [CXD9872AKD_VAIO] = "vaio-ar",
4991};
4992
4993static struct snd_pci_quirk stac9872_cfg_tbl[] = {
4994 SND_PCI_QUIRK(0x104d, 0x81e6, "Sony VAIO F/S", CXD9872RD_VAIO),
4995 SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
4996 SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
Tobin Davis68e22542007-03-12 11:36:39 +01004997 SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
Takashi Iwaidb064e52006-03-16 16:04:58 +01004998 {}
4999};
5000
Guillaume Munch6d859062006-08-22 17:15:47 +02005001static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01005002{
5003 struct sigmatel_spec *spec;
5004 int board_config;
5005
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005006 board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS,
5007 stac9872_models,
5008 stac9872_cfg_tbl);
Takashi Iwaidb064e52006-03-16 16:04:58 +01005009 if (board_config < 0)
5010 /* unknown config, let generic-parser do its job... */
5011 return snd_hda_parse_generic_codec(codec);
5012
5013 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5014 if (spec == NULL)
5015 return -ENOMEM;
5016
5017 codec->spec = spec;
5018 switch (board_config) {
Guillaume Munch6d859062006-08-22 17:15:47 +02005019 case CXD9872RD_VAIO:
5020 case STAC9872AK_VAIO:
5021 case STAC9872K_VAIO:
Takashi Iwaidb064e52006-03-16 16:04:58 +01005022 spec->mixer = vaio_mixer;
5023 spec->init = vaio_init;
5024 spec->multiout.max_channels = 2;
5025 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5026 spec->multiout.dac_nids = vaio_dacs;
5027 spec->multiout.hp_nid = VAIO_HP_DAC;
5028 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
5029 spec->adc_nids = vaio_adcs;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005030 spec->num_pwrs = 0;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005031 spec->input_mux = &vaio_mux;
5032 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005033 codec->patch_ops = stac9872_vaio_patch_ops;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005034 break;
Guillaume Munch6d859062006-08-22 17:15:47 +02005035
5036 case CXD9872AKD_VAIO:
5037 spec->mixer = vaio_ar_mixer;
5038 spec->init = vaio_ar_init;
5039 spec->multiout.max_channels = 2;
5040 spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
5041 spec->multiout.dac_nids = vaio_dacs;
5042 spec->multiout.hp_nid = VAIO_HP_DAC;
5043 spec->num_adcs = ARRAY_SIZE(vaio_adcs);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005044 spec->num_pwrs = 0;
Guillaume Munch6d859062006-08-22 17:15:47 +02005045 spec->adc_nids = vaio_adcs;
5046 spec->input_mux = &vaio_mux;
5047 spec->mux_nids = vaio_mux_nids;
Takashi Iwai72e7b0d2007-08-16 17:33:55 +02005048 codec->patch_ops = stac9872_patch_ops;
Guillaume Munch6d859062006-08-22 17:15:47 +02005049 break;
Takashi Iwaidb064e52006-03-16 16:04:58 +01005050 }
5051
Takashi Iwaidb064e52006-03-16 16:04:58 +01005052 return 0;
5053}
5054
5055
5056/*
Matt2f2f4252005-04-13 14:45:30 +02005057 * patch entries
5058 */
5059struct hda_codec_preset snd_hda_preset_sigmatel[] = {
5060 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
5061 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
5062 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
5063 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
5064 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
5065 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
5066 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02005067 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
5068 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
5069 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
5070 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
5071 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
5072 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01005073 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
5074 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
5075 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
5076 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
5077 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
5078 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
5079 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
5080 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
5081 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
5082 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01005083 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
5084 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
5085 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
5086 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
5087 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
5088 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02005089 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
5090 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02005091 /* The following does not take into account .id=0x83847661 when subsys =
5092 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
5093 * currently not fully supported.
5094 */
5095 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
5096 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
5097 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Matt Porterf3302a52006-07-31 12:49:34 +02005098 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
5099 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
5100 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
5101 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
5102 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
5103 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
5104 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
5105 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005106 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005107 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
5108 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02005109 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01005110 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
5111 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005112 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01005113 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5114 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
5115 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5116 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
5117 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5118 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
5119 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
5120 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Matt2f2f4252005-04-13 14:45:30 +02005121 {} /* terminator */
5122};