blob: 60d43dd3e061533fd92ec4162aa2fdc9d4777829 [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>
Vitaliy Kulikov5bdaaad2009-11-04 07:57:45 +010031#include <linux/dmi.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040032#include <linux/module.h>
Matt2f2f4252005-04-13 14:45:30 +020033#include <sound/core.h>
Mattc7d4b2f2005-06-27 14:59:41 +020034#include <sound/asoundef.h>
Matthew Ranostay45a6ac12008-10-15 14:45:38 -040035#include <sound/jack.h>
Clemens Ladischa74ccea2010-10-22 15:52:34 +020036#include <sound/tlv.h>
Matt2f2f4252005-04-13 14:45:30 +020037#include "hda_codec.h"
38#include "hda_local.h"
Takashi Iwai128bc4b2012-05-07 17:42:31 +020039#include "hda_auto_parser.h"
Matthew Ranostay1cd22242008-07-18 18:20:52 +020040#include "hda_beep.h"
Takashi Iwai1835a0f2011-10-27 22:12:46 +020041#include "hda_jack.h"
Matt2f2f4252005-04-13 14:45:30 +020042
Takashi Iwaic6e4c662008-11-25 11:58:19 +010043enum {
44 STAC_VREF_EVENT = 1,
45 STAC_INSERT_EVENT,
46 STAC_PWR_EVENT,
47 STAC_HP_EVENT,
Takashi Iwaifefd67f2009-07-30 18:03:05 +020048 STAC_LO_EVENT,
Takashi Iwai3d21d3f2009-07-29 14:32:56 +020049 STAC_MIC_EVENT,
Takashi Iwaic6e4c662008-11-25 11:58:19 +010050};
Matt4e550962005-07-04 17:51:39 +020051
Takashi Iwaif5fcc132006-11-24 17:07:44 +010052enum {
53 STAC_REF,
Tobin Davisbf277782008-02-03 20:31:47 +010054 STAC_9200_OQO,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020055 STAC_9200_DELL_D21,
56 STAC_9200_DELL_D22,
57 STAC_9200_DELL_D23,
58 STAC_9200_DELL_M21,
59 STAC_9200_DELL_M22,
60 STAC_9200_DELL_M23,
61 STAC_9200_DELL_M24,
62 STAC_9200_DELL_M25,
63 STAC_9200_DELL_M26,
64 STAC_9200_DELL_M27,
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +020065 STAC_9200_M4,
66 STAC_9200_M4_2,
Takashi Iwai117f2572008-03-18 09:53:23 +010067 STAC_9200_PANASONIC,
Takashi Iwaid39a3ae2013-01-14 14:06:26 +010068 STAC_9200_EAPD_INIT,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010069 STAC_9200_MODELS
70};
71
72enum {
73 STAC_9205_REF,
Takashi Iwaidfe495d2007-08-23 19:04:28 +020074 STAC_9205_DELL_M42,
Tobin Davisae0a8ed2007-08-13 15:50:29 +020075 STAC_9205_DELL_M43,
76 STAC_9205_DELL_M44,
Takashi Iwaid9a42682009-01-22 17:40:18 +010077 STAC_9205_EAPD,
Takashi Iwaif5fcc132006-11-24 17:07:44 +010078 STAC_9205_MODELS
79};
80
81enum {
Takashi Iwai1607b8e2009-02-26 16:50:43 +010082 STAC_92HD73XX_AUTO,
Takashi Iwai9e43f0d2008-12-17 14:51:01 +010083 STAC_92HD73XX_NO_JD, /* no jack-detection */
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010084 STAC_92HD73XX_REF,
Wu Fengguangae709442009-08-19 17:05:11 +080085 STAC_92HD73XX_INTEL,
Takashi Iwai661cd8f2008-11-25 15:18:29 +010086 STAC_DELL_M6_AMIC,
87 STAC_DELL_M6_DMIC,
88 STAC_DELL_M6_BOTH,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -050089 STAC_DELL_EQ,
Takashi Iwai842ae632009-09-02 07:43:08 +020090 STAC_ALIENWARE_M17X,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +010091 STAC_92HD73XX_MODELS
92};
93
94enum {
Takashi Iwai1607b8e2009-02-26 16:50:43 +010095 STAC_92HD83XXX_AUTO,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +020096 STAC_92HD83XXX_REF,
Matthew Ranostay32ed3f42009-01-22 20:53:29 -050097 STAC_92HD83XXX_PWR_REF,
Matthew Ranostay8bb0ac52009-02-12 16:50:01 -050098 STAC_DELL_S14,
Julian Wollrathf7f9bdf2011-11-09 10:02:40 +010099 STAC_DELL_VOSTRO_3500,
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -0500100 STAC_92HD83XXX_HP_cNB11_INTQUAD,
Steven Eastland48315592010-08-06 15:07:35 -0600101 STAC_HP_DV7_4000,
Vitaliy Kulikov5556e142012-02-27 16:47:37 -0600102 STAC_HP_ZEPHYR,
Takashi Iwaia3e19972012-07-26 08:17:20 +0200103 STAC_92HD83XXX_HP_LED,
Takashi Iwaiff8a1e22012-07-31 10:16:59 +0200104 STAC_92HD83XXX_HP_INV_LED,
Takashi Iwai62cbde12012-09-14 11:58:54 +0200105 STAC_92HD83XXX_HP_MIC_LED,
David Henningsson8d032a82012-10-09 12:48:40 +0200106 STAC_92HD83XXX_HEADSET_JACK,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200107 STAC_92HD83XXX_MODELS
108};
109
110enum {
Takashi Iwai1607b8e2009-02-26 16:50:43 +0100111 STAC_92HD71BXX_AUTO,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100112 STAC_92HD71BXX_REF,
Matthew Ranostaya7662642008-02-21 07:51:14 +0100113 STAC_DELL_M4_1,
114 STAC_DELL_M4_2,
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -0500115 STAC_DELL_M4_3,
Matthew Ranostay6a14f582008-09-12 12:02:30 -0400116 STAC_HP_M4,
Takashi Iwai2a6ce6e2010-05-12 10:16:20 +0200117 STAC_HP_DV4,
Takashi Iwai1b0652e2009-01-14 08:27:35 +0100118 STAC_HP_DV5,
Christoph Plattnerae6241f2009-03-08 23:19:05 +0100119 STAC_HP_HDX,
James Gardiner514bf542009-05-03 04:00:44 -0400120 STAC_HP_DV4_1222NR,
Matthew Ranostaye035b842007-11-06 11:53:55 +0100121 STAC_92HD71BXX_MODELS
122};
123
124enum {
Tobin Davis8e21c342007-01-08 11:04:17 +0100125 STAC_925x_REF,
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +0200126 STAC_M1,
127 STAC_M1_2,
128 STAC_M2,
Tobin Davis8e21c342007-01-08 11:04:17 +0100129 STAC_M2_2,
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +0200130 STAC_M3,
131 STAC_M5,
132 STAC_M6,
Tobin Davis8e21c342007-01-08 11:04:17 +0100133 STAC_925x_MODELS
134};
135
136enum {
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100137 STAC_D945_REF,
138 STAC_D945GTP3,
139 STAC_D945GTP5,
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +0200140 STAC_INTEL_MAC_V1,
141 STAC_INTEL_MAC_V2,
142 STAC_INTEL_MAC_V3,
143 STAC_INTEL_MAC_V4,
144 STAC_INTEL_MAC_V5,
Takashi Iwai0a427842013-01-14 15:20:13 +0100145 STAC_INTEL_MAC_AUTO,
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -0300146 STAC_ECS_202,
Takashi Iwaidfe495d2007-08-23 19:04:28 +0200147 STAC_922X_DELL_D81,
148 STAC_922X_DELL_D82,
149 STAC_922X_DELL_M81,
150 STAC_922X_DELL_M82,
Takashi Iwai0a427842013-01-14 15:20:13 +0100151 STAC_922X_INTEL_MAC_GPIO,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100152 STAC_922X_MODELS
153};
154
155enum {
Takashi Iwai1607b8e2009-02-26 16:50:43 +0100156 STAC_927X_AUTO,
Takashi Iwaie28d8322008-12-17 13:48:29 +0100157 STAC_D965_REF_NO_JD, /* no jack-detection */
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100158 STAC_D965_REF,
159 STAC_D965_3ST,
160 STAC_D965_5ST,
Takashi Iwai679d92e2009-05-24 19:00:08 +0200161 STAC_D965_5ST_NO_FP,
Tobin Davis4ff076e2007-08-07 11:48:12 +0200162 STAC_DELL_3ST,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +0100163 STAC_DELL_BIOS,
Takashi Iwai54930532009-10-11 17:38:29 +0200164 STAC_927X_VOLKNOB,
Takashi Iwaif5fcc132006-11-24 17:07:44 +0100165 STAC_927X_MODELS
166};
Matt Porter403d1942005-11-29 15:00:51 +0100167
Takashi Iwai307282c2009-03-12 18:17:58 +0100168enum {
Takashi Iwai307282c2009-03-12 18:17:58 +0100169 STAC_9872_VAIO,
170 STAC_9872_MODELS
171};
172
Takashi Iwai3d21d3f2009-07-29 14:32:56 +0200173struct sigmatel_mic_route {
174 hda_nid_t pin;
Takashi Iwai02d33322009-10-01 16:38:11 +0200175 signed char mux_idx;
176 signed char dmux_idx;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +0200177};
178
Vitaliy Kulikov699d8992011-03-10 13:43:35 -0600179#define MAX_PINS_NUM 16
180#define MAX_ADCS_NUM 4
181#define MAX_DMICS_NUM 4
182
Matt2f2f4252005-04-13 14:45:30 +0200183struct sigmatel_spec {
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100184 struct snd_kcontrol_new *mixers[4];
Mattc7d4b2f2005-06-27 14:59:41 +0200185 unsigned int num_mixers;
186
Matt Porter403d1942005-11-29 15:00:51 +0100187 int board_config;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -0500188 unsigned int eapd_switch: 1;
Mattc7d4b2f2005-06-27 14:59:41 +0200189 unsigned int surr_switch: 1;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100190 unsigned int alt_switch: 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +0100191 unsigned int hp_detect: 1;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400192 unsigned int spdif_mute: 1;
Takashi Iwai7c7767e2009-01-20 15:28:38 +0100193 unsigned int check_volume_offset:1;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +0200194 unsigned int auto_mic:1;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +0100195 unsigned int linear_tone_beep:1;
David Henningsson8d032a82012-10-09 12:48:40 +0200196 unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */
Mattc7d4b2f2005-06-27 14:59:41 +0200197
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100198 /* gpio lines */
Matthew Ranostay0fc9dec2008-04-14 13:32:54 +0200199 unsigned int eapd_mask;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100200 unsigned int gpio_mask;
201 unsigned int gpio_dir;
202 unsigned int gpio_data;
203 unsigned int gpio_mute;
Takashi Iwai86d190e2009-05-26 15:18:58 +0200204 unsigned int gpio_led;
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +0100205 unsigned int gpio_led_polarity;
Takashi Iwaif1a73742011-12-04 13:44:06 +0100206 unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -0500207 unsigned int vref_led;
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100208
Takashi Iwai62cbde12012-09-14 11:58:54 +0200209 unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
210 bool mic_mute_led_on; /* current mic mute state */
211
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200212 /* stream */
213 unsigned int stream_delay;
214
Matthew Ranostay4fe51952008-01-29 15:28:44 +0100215 /* analog loopback */
Takashi Iwai2b635362011-05-02 12:33:43 +0200216 const struct snd_kcontrol_new *aloopback_ctl;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100217 unsigned char aloopback_mask;
218 unsigned char aloopback_shift;
Takashi Iwai82599802007-07-31 15:56:24 +0200219
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100220 /* power management */
Takashi Iwaic8822462012-05-15 09:11:36 +0200221 unsigned int power_map_bits;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100222 unsigned int num_pwrs;
Takashi Iwai2b635362011-05-02 12:33:43 +0200223 const hda_nid_t *pwr_nids;
224 const hda_nid_t *dac_list;
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100225
Matt2f2f4252005-04-13 14:45:30 +0200226 /* playback */
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100227 struct hda_input_mux *mono_mux;
228 unsigned int cur_mmux;
Matt2f2f4252005-04-13 14:45:30 +0200229 struct hda_multi_out multiout;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100230 hda_nid_t dac_nids[5];
Takashi Iwaic21ca4a2008-12-19 09:26:08 +0100231 hda_nid_t hp_dacs[5];
232 hda_nid_t speaker_dacs[5];
Matt2f2f4252005-04-13 14:45:30 +0200233
Takashi Iwai7c7767e2009-01-20 15:28:38 +0100234 int volume_offset;
235
Matt2f2f4252005-04-13 14:45:30 +0200236 /* capture */
Takashi Iwai2b635362011-05-02 12:33:43 +0200237 const hda_nid_t *adc_nids;
Matt2f2f4252005-04-13 14:45:30 +0200238 unsigned int num_adcs;
Takashi Iwai2b635362011-05-02 12:33:43 +0200239 const hda_nid_t *mux_nids;
Mattdabbed62005-06-14 10:19:34 +0200240 unsigned int num_muxes;
Takashi Iwai2b635362011-05-02 12:33:43 +0200241 const hda_nid_t *dmic_nids;
Matt Porter8b657272006-10-26 17:12:59 +0200242 unsigned int num_dmics;
Takashi Iwai2b635362011-05-02 12:33:43 +0200243 const hda_nid_t *dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +0100244 unsigned int num_dmuxes;
Takashi Iwai2b635362011-05-02 12:33:43 +0200245 const hda_nid_t *smux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200246 unsigned int num_smuxes;
Takashi Iwai5207e102009-07-30 13:09:08 +0200247 unsigned int num_analog_muxes;
Takashi Iwai6479c632009-07-28 18:20:25 +0200248
Takashi Iwai2b635362011-05-02 12:33:43 +0200249 const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */
250 const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */
Takashi Iwai6479c632009-07-28 18:20:25 +0200251 unsigned int num_caps; /* number of capture volume/switch elements */
252
Takashi Iwai3d21d3f2009-07-29 14:32:56 +0200253 struct sigmatel_mic_route ext_mic;
254 struct sigmatel_mic_route int_mic;
Charles Chin99077902010-09-17 10:22:32 +0200255 struct sigmatel_mic_route dock_mic;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +0200256
Takashi Iwaiea734962011-01-17 11:29:34 +0100257 const char * const *spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200258
Mattdabbed62005-06-14 10:19:34 +0200259 hda_nid_t dig_in_nid;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100260 hda_nid_t mono_nid;
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200261 hda_nid_t anabeep_nid;
262 hda_nid_t digbeep_nid;
Matt2f2f4252005-04-13 14:45:30 +0200263
Matt2f2f4252005-04-13 14:45:30 +0200264 /* pin widgets */
Takashi Iwai2b635362011-05-02 12:33:43 +0200265 const hda_nid_t *pin_nids;
Matt2f2f4252005-04-13 14:45:30 +0200266 unsigned int num_pins;
Matt2f2f4252005-04-13 14:45:30 +0200267
268 /* codec specific stuff */
Takashi Iwai2b635362011-05-02 12:33:43 +0200269 const struct hda_verb *init;
270 const struct snd_kcontrol_new *mixer;
Matt2f2f4252005-04-13 14:45:30 +0200271
272 /* capture source */
Matt Porter8b657272006-10-26 17:12:59 +0200273 struct hda_input_mux *dinput_mux;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100274 unsigned int cur_dmux[2];
Mattc7d4b2f2005-06-27 14:59:41 +0200275 struct hda_input_mux *input_mux;
Matt Porter3cc08dc2006-01-23 15:27:49 +0100276 unsigned int cur_mux[3];
Matthew Ranostayd9737752008-09-07 12:03:41 +0200277 struct hda_input_mux *sinput_mux;
278 unsigned int cur_smux[2];
Matthew Ranostay2a9c7812008-09-13 16:45:39 -0400279 unsigned int cur_amux;
280 hda_nid_t *amp_nids;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +0200281 unsigned int powerdown_adcs;
Matt2f2f4252005-04-13 14:45:30 +0200282
Matt Porter403d1942005-11-29 15:00:51 +0100283 /* i/o switches */
284 unsigned int io_switch[2];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +0200285 unsigned int clfe_swap;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +0100286 hda_nid_t line_switch; /* shared line-in for input and output */
287 hda_nid_t mic_switch; /* shared mic-in for input and output */
288 hda_nid_t hp_switch; /* NID of HP as line-out */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200289 unsigned int aloopback;
Matt2f2f4252005-04-13 14:45:30 +0200290
Mattc7d4b2f2005-06-27 14:59:41 +0200291 struct hda_pcm pcm_rec[2]; /* PCM information */
292
293 /* dynamic controls and input_mux */
294 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200295 struct snd_array kctls;
Matt Porter8b657272006-10-26 17:12:59 +0200296 struct hda_input_mux private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +0200297 struct hda_input_mux private_imux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200298 struct hda_input_mux private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100299 struct hda_input_mux private_mono_mux;
Vitaliy Kulikov699d8992011-03-10 13:43:35 -0600300
301 /* auto spec */
302 unsigned auto_pin_cnt;
303 hda_nid_t auto_pin_nids[MAX_PINS_NUM];
304 unsigned auto_adc_cnt;
305 hda_nid_t auto_adc_nids[MAX_ADCS_NUM];
306 hda_nid_t auto_mux_nids[MAX_ADCS_NUM];
307 hda_nid_t auto_dmux_nids[MAX_ADCS_NUM];
308 unsigned long auto_capvols[MAX_ADCS_NUM];
309 unsigned auto_dmic_cnt;
310 hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
Takashi Iwai2faa3bf2012-03-12 12:30:22 +0100311
Takashi Iwaid2f344b2012-03-12 16:59:58 +0100312 struct hda_vmaster_mute_hook vmaster_mute;
Matt2f2f4252005-04-13 14:45:30 +0200313};
314
Takashi Iwaic8822462012-05-15 09:11:36 +0200315#define AC_VERB_IDT_SET_POWER_MAP 0x7ec
316#define AC_VERB_IDT_GET_POWER_MAP 0xfec
317
Takashi Iwai2b635362011-05-02 12:33:43 +0200318static const hda_nid_t stac9200_adc_nids[1] = {
Matt2f2f4252005-04-13 14:45:30 +0200319 0x03,
320};
321
Takashi Iwai2b635362011-05-02 12:33:43 +0200322static const hda_nid_t stac9200_mux_nids[1] = {
Matt2f2f4252005-04-13 14:45:30 +0200323 0x0c,
324};
325
Takashi Iwai2b635362011-05-02 12:33:43 +0200326static const hda_nid_t stac9200_dac_nids[1] = {
Matt2f2f4252005-04-13 14:45:30 +0200327 0x02,
328};
329
Takashi Iwai2b635362011-05-02 12:33:43 +0200330static const hda_nid_t stac92hd73xx_pwr_nids[8] = {
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100331 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
332 0x0f, 0x10, 0x11
333};
334
Takashi Iwai2b635362011-05-02 12:33:43 +0200335static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = {
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400336 0x26, 0,
337};
338
Takashi Iwai2b635362011-05-02 12:33:43 +0200339static const hda_nid_t stac92hd73xx_adc_nids[2] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100340 0x1a, 0x1b
341};
342
343#define STAC92HD73XX_NUM_DMICS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200344static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100345 0x13, 0x14, 0
346};
347
348#define STAC92HD73_DAC_COUNT 5
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100349
Takashi Iwai2b635362011-05-02 12:33:43 +0200350static const hda_nid_t stac92hd73xx_mux_nids[2] = {
Takashi Iwaie2aec172009-09-02 01:00:05 +0200351 0x20, 0x21,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100352};
353
Takashi Iwai2b635362011-05-02 12:33:43 +0200354static const hda_nid_t stac92hd73xx_dmux_nids[2] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100355 0x20, 0x21,
356};
357
Takashi Iwai2b635362011-05-02 12:33:43 +0200358static const hda_nid_t stac92hd73xx_smux_nids[2] = {
Matthew Ranostayd9737752008-09-07 12:03:41 +0200359 0x22, 0x23,
360};
361
Takashi Iwai6479c632009-07-28 18:20:25 +0200362#define STAC92HD73XX_NUM_CAPS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200363static const unsigned long stac92hd73xx_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200364 HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT),
365 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
366};
367#define stac92hd73xx_capsws stac92hd73xx_capvols
368
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200369#define STAC92HD83_DAC_COUNT 3
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200370
Charles Chinafef2cf2011-11-11 08:05:28 +0100371static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
372 0x0a, 0x0b, 0x0c, 0xd, 0x0e,
373 0x0f, 0x10
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200374};
375
Takashi Iwai2b635362011-05-02 12:33:43 +0200376static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400377 0x1e, 0,
378};
379
Takashi Iwai2b635362011-05-02 12:33:43 +0200380static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
Vitaliy Kulikov699d8992011-03-10 13:43:35 -0600381 0x11, 0x20,
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +0200382};
383
Takashi Iwai2b635362011-05-02 12:33:43 +0200384static const hda_nid_t stac92hd71bxx_pwr_nids[3] = {
Matthew Ranostaya64135a2008-01-10 16:55:06 +0100385 0x0a, 0x0d, 0x0f
386};
387
Takashi Iwai2b635362011-05-02 12:33:43 +0200388static const hda_nid_t stac92hd71bxx_adc_nids[2] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100389 0x12, 0x13,
390};
391
Takashi Iwai2b635362011-05-02 12:33:43 +0200392static const hda_nid_t stac92hd71bxx_mux_nids[2] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100393 0x1a, 0x1b
394};
395
Takashi Iwai2b635362011-05-02 12:33:43 +0200396static const hda_nid_t stac92hd71bxx_dmux_nids[2] = {
Matthew Ranostay4b33c762008-10-10 09:07:23 -0400397 0x1c, 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100398};
399
Takashi Iwai2b635362011-05-02 12:33:43 +0200400static const hda_nid_t stac92hd71bxx_smux_nids[2] = {
Matthew Ranostayd9737752008-09-07 12:03:41 +0200401 0x24, 0x25,
402};
403
Matthew Ranostaye035b842007-11-06 11:53:55 +0100404#define STAC92HD71BXX_NUM_DMICS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200405static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100406 0x18, 0x19, 0
407};
408
Takashi Iwai2b635362011-05-02 12:33:43 +0200409static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = {
410 0x18, 0
411};
412
413static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = {
Matthew Ranostay0ffa9802008-09-08 11:20:05 -0400414 0x22, 0
415};
416
Takashi Iwai6479c632009-07-28 18:20:25 +0200417#define STAC92HD71BXX_NUM_CAPS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200418static const unsigned long stac92hd71bxx_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200419 HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
420 HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
421};
422#define stac92hd71bxx_capsws stac92hd71bxx_capvols
423
Takashi Iwai2b635362011-05-02 12:33:43 +0200424static const hda_nid_t stac925x_adc_nids[1] = {
Tobin Davis8e21c342007-01-08 11:04:17 +0100425 0x03,
426};
427
Takashi Iwai2b635362011-05-02 12:33:43 +0200428static const hda_nid_t stac925x_mux_nids[1] = {
Tobin Davis8e21c342007-01-08 11:04:17 +0100429 0x0f,
430};
431
Takashi Iwai2b635362011-05-02 12:33:43 +0200432static const hda_nid_t stac925x_dac_nids[1] = {
Tobin Davis8e21c342007-01-08 11:04:17 +0100433 0x02,
434};
435
Takashi Iwaif6e98522007-10-16 14:27:04 +0200436#define STAC925X_NUM_DMICS 1
Takashi Iwai2b635362011-05-02 12:33:43 +0200437static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
Takashi Iwaif6e98522007-10-16 14:27:04 +0200438 0x15, 0
Tobin Davis2c11f952007-05-17 09:36:34 +0200439};
440
Takashi Iwai2b635362011-05-02 12:33:43 +0200441static const hda_nid_t stac925x_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100442 0x14,
443};
444
Takashi Iwai2b635362011-05-02 12:33:43 +0200445static const unsigned long stac925x_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200446 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
447};
Takashi Iwai2b635362011-05-02 12:33:43 +0200448static const unsigned long stac925x_capsws[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200449 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
450};
451
Takashi Iwai2b635362011-05-02 12:33:43 +0200452static const hda_nid_t stac922x_adc_nids[2] = {
Matt2f2f4252005-04-13 14:45:30 +0200453 0x06, 0x07,
454};
455
Takashi Iwai2b635362011-05-02 12:33:43 +0200456static const hda_nid_t stac922x_mux_nids[2] = {
Matt2f2f4252005-04-13 14:45:30 +0200457 0x12, 0x13,
458};
459
Takashi Iwai6479c632009-07-28 18:20:25 +0200460#define STAC922X_NUM_CAPS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200461static const unsigned long stac922x_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200462 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT),
463 HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
464};
465#define stac922x_capsws stac922x_capvols
466
Takashi Iwai2b635362011-05-02 12:33:43 +0200467static const hda_nid_t stac927x_slave_dig_outs[2] = {
Matthew Ranostay45c1d852009-02-04 17:49:41 -0500468 0x1f, 0,
469};
470
Takashi Iwai2b635362011-05-02 12:33:43 +0200471static const hda_nid_t stac927x_adc_nids[3] = {
Matt Porter3cc08dc2006-01-23 15:27:49 +0100472 0x07, 0x08, 0x09
473};
474
Takashi Iwai2b635362011-05-02 12:33:43 +0200475static const hda_nid_t stac927x_mux_nids[3] = {
Matt Porter3cc08dc2006-01-23 15:27:49 +0100476 0x15, 0x16, 0x17
477};
478
Takashi Iwai2b635362011-05-02 12:33:43 +0200479static const hda_nid_t stac927x_smux_nids[1] = {
Matthew Ranostayd9737752008-09-07 12:03:41 +0200480 0x21,
481};
482
Takashi Iwai2b635362011-05-02 12:33:43 +0200483static const hda_nid_t stac927x_dac_nids[6] = {
Matthew Ranostayb76c8502008-02-06 14:49:44 +0100484 0x02, 0x03, 0x04, 0x05, 0x06, 0
485};
486
Takashi Iwai2b635362011-05-02 12:33:43 +0200487static const hda_nid_t stac927x_dmux_nids[1] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100488 0x1b,
489};
490
Matthew Ranostay7f168592007-10-18 17:38:17 +0200491#define STAC927X_NUM_DMICS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200492static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
Matthew Ranostay7f168592007-10-18 17:38:17 +0200493 0x13, 0x14, 0
494};
495
Takashi Iwai6479c632009-07-28 18:20:25 +0200496#define STAC927X_NUM_CAPS 3
Takashi Iwai2b635362011-05-02 12:33:43 +0200497static const unsigned long stac927x_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200498 HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT),
499 HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT),
500 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT),
501};
Takashi Iwai2b635362011-05-02 12:33:43 +0200502static const unsigned long stac927x_capsws[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200503 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
504 HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT),
505 HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
506};
507
Takashi Iwaiea734962011-01-17 11:29:34 +0100508static const char * const stac927x_spdif_labels[5] = {
Matthew Ranostay65973632008-09-16 10:39:37 -0400509 "Digital Playback", "ADAT", "Analog Mux 1",
510 "Analog Mux 2", "Analog Mux 3"
511};
512
Takashi Iwai2b635362011-05-02 12:33:43 +0200513static const hda_nid_t stac9205_adc_nids[2] = {
Matt Porterf3302a52006-07-31 12:49:34 +0200514 0x12, 0x13
515};
516
Takashi Iwai2b635362011-05-02 12:33:43 +0200517static const hda_nid_t stac9205_mux_nids[2] = {
Matt Porterf3302a52006-07-31 12:49:34 +0200518 0x19, 0x1a
519};
520
Takashi Iwai2b635362011-05-02 12:33:43 +0200521static const hda_nid_t stac9205_dmux_nids[1] = {
Takashi Iwai1697055e2007-12-18 18:05:52 +0100522 0x1d,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100523};
524
Takashi Iwai2b635362011-05-02 12:33:43 +0200525static const hda_nid_t stac9205_smux_nids[1] = {
Matthew Ranostayd9737752008-09-07 12:03:41 +0200526 0x21,
527};
528
Takashi Iwaif6e98522007-10-16 14:27:04 +0200529#define STAC9205_NUM_DMICS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200530static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
Takashi Iwaif6e98522007-10-16 14:27:04 +0200531 0x17, 0x18, 0
Matt Porter8b657272006-10-26 17:12:59 +0200532};
533
Takashi Iwai6479c632009-07-28 18:20:25 +0200534#define STAC9205_NUM_CAPS 2
Takashi Iwai2b635362011-05-02 12:33:43 +0200535static const unsigned long stac9205_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200536 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT),
537 HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT),
538};
Takashi Iwai2b635362011-05-02 12:33:43 +0200539static const unsigned long stac9205_capsws[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +0200540 HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
541 HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT),
542};
543
Takashi Iwai2b635362011-05-02 12:33:43 +0200544static const hda_nid_t stac9200_pin_nids[8] = {
Tobin Davis93ed1502006-09-01 21:03:12 +0200545 0x08, 0x09, 0x0d, 0x0e,
546 0x0f, 0x10, 0x11, 0x12,
Matt2f2f4252005-04-13 14:45:30 +0200547};
548
Takashi Iwai2b635362011-05-02 12:33:43 +0200549static const hda_nid_t stac925x_pin_nids[8] = {
Tobin Davis8e21c342007-01-08 11:04:17 +0100550 0x07, 0x08, 0x0a, 0x0b,
551 0x0c, 0x0d, 0x10, 0x11,
552};
553
Takashi Iwai2b635362011-05-02 12:33:43 +0200554static const hda_nid_t stac922x_pin_nids[10] = {
Matt2f2f4252005-04-13 14:45:30 +0200555 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
556 0x0f, 0x10, 0x11, 0x15, 0x1b,
557};
558
Takashi Iwai2b635362011-05-02 12:33:43 +0200559static const hda_nid_t stac92hd73xx_pin_nids[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100560 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
561 0x0f, 0x10, 0x11, 0x12, 0x13,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200562 0x14, 0x22, 0x23
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100563};
564
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -0500565#define STAC92HD71BXX_NUM_PINS 13
Takashi Iwai2b635362011-05-02 12:33:43 +0200566static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -0500567 0x0a, 0x0b, 0x0c, 0x0d, 0x00,
568 0x00, 0x14, 0x18, 0x19, 0x1e,
569 0x1f, 0x20, 0x27
570};
Takashi Iwai2b635362011-05-02 12:33:43 +0200571static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100572 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
573 0x0f, 0x14, 0x18, 0x19, 0x1e,
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -0500574 0x1f, 0x20, 0x27
Matthew Ranostaye035b842007-11-06 11:53:55 +0100575};
576
Takashi Iwai2b635362011-05-02 12:33:43 +0200577static const hda_nid_t stac927x_pin_nids[14] = {
Matt Porter3cc08dc2006-01-23 15:27:49 +0100578 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
579 0x0f, 0x10, 0x11, 0x12, 0x13,
580 0x14, 0x21, 0x22, 0x23,
581};
582
Takashi Iwai2b635362011-05-02 12:33:43 +0200583static const hda_nid_t stac9205_pin_nids[12] = {
Matt Porterf3302a52006-07-31 12:49:34 +0200584 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
585 0x0f, 0x14, 0x16, 0x17, 0x18,
586 0x21, 0x22,
Matt Porterf3302a52006-07-31 12:49:34 +0200587};
588
Matt Porter8b657272006-10-26 17:12:59 +0200589static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
590 struct snd_ctl_elem_info *uinfo)
591{
592 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
593 struct sigmatel_spec *spec = codec->spec;
594 return snd_hda_input_mux_info(spec->dinput_mux, uinfo);
595}
596
597static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
598 struct snd_ctl_elem_value *ucontrol)
599{
600 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
601 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100602 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200603
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100604 ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
Matt Porter8b657272006-10-26 17:12:59 +0200605 return 0;
606}
607
608static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
609 struct snd_ctl_elem_value *ucontrol)
610{
611 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
612 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100613 unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matt Porter8b657272006-10-26 17:12:59 +0200614
615 return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100616 spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
Matt Porter8b657272006-10-26 17:12:59 +0200617}
618
Matthew Ranostayd9737752008-09-07 12:03:41 +0200619static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol,
620 struct snd_ctl_elem_info *uinfo)
621{
622 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
623 struct sigmatel_spec *spec = codec->spec;
624 return snd_hda_input_mux_info(spec->sinput_mux, uinfo);
625}
626
627static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol,
628 struct snd_ctl_elem_value *ucontrol)
629{
630 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
631 struct sigmatel_spec *spec = codec->spec;
632 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
633
634 ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
635 return 0;
636}
637
638static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
639 struct snd_ctl_elem_value *ucontrol)
640{
641 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
642 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400643 struct hda_input_mux *smux = &spec->private_smux;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200644 unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400645 int err, val;
646 hda_nid_t nid;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200647
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400648 err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol,
Matthew Ranostayd9737752008-09-07 12:03:41 +0200649 spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400650 if (err < 0)
651 return err;
652
653 if (spec->spdif_mute) {
654 if (smux_idx == 0)
655 nid = spec->multiout.dig_out_nid;
656 else
657 nid = codec->slave_dig_outs[smux_idx - 1];
658 if (spec->cur_smux[smux_idx] == smux->num_items - 1)
Takashi Iwaic9b46f92008-12-01 11:42:09 +0100659 val = HDA_AMP_MUTE;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400660 else
Takashi Iwaic9b46f92008-12-01 11:42:09 +0100661 val = 0;
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400662 /* un/mute SPDIF out */
Takashi Iwaic9b46f92008-12-01 11:42:09 +0100663 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
664 HDA_AMP_MUTE, val);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -0400665 }
666 return 0;
Matthew Ranostayd9737752008-09-07 12:03:41 +0200667}
668
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -0500669static int stac_vrefout_set(struct hda_codec *codec,
670 hda_nid_t nid, unsigned int new_vref)
671{
672 int error, pinctl;
673
674 snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref);
675 pinctl = snd_hda_codec_read(codec, nid, 0,
676 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
677
678 if (pinctl < 0)
679 return pinctl;
680
681 pinctl &= 0xff;
682 pinctl &= ~AC_PINCTL_VREFEN;
683 pinctl |= (new_vref & AC_PINCTL_VREFEN);
684
Takashi Iwaicdd03ce2012-04-20 12:34:50 +0200685 error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -0500686 if (error < 0)
687 return error;
688
689 return 1;
690}
691
Nickolas Lloyd2fc99892009-05-15 15:33:30 +0200692static unsigned int stac92xx_vref_set(struct hda_codec *codec,
693 hda_nid_t nid, unsigned int new_vref)
694{
Takashi Iwaib8621512009-06-22 08:00:10 +0200695 int error;
Nickolas Lloyd2fc99892009-05-15 15:33:30 +0200696 unsigned int pincfg;
697 pincfg = snd_hda_codec_read(codec, nid, 0,
698 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
699
700 pincfg &= 0xff;
701 pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
702 pincfg |= new_vref;
703
704 if (new_vref == AC_PINCTL_VREF_HIZ)
705 pincfg |= AC_PINCTL_OUT_EN;
706 else
707 pincfg |= AC_PINCTL_IN_EN;
708
Takashi Iwaicdd03ce2012-04-20 12:34:50 +0200709 error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg);
Nickolas Lloyd2fc99892009-05-15 15:33:30 +0200710 if (error < 0)
711 return error;
712 else
713 return 1;
714}
715
716static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid)
717{
718 unsigned int vref;
719 vref = snd_hda_codec_read(codec, nid, 0,
720 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
721 vref &= AC_PINCTL_VREFEN;
722 return vref;
723}
724
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100725static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Matt2f2f4252005-04-13 14:45:30 +0200726{
727 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
728 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +0200729 return snd_hda_input_mux_info(spec->input_mux, uinfo);
Matt2f2f4252005-04-13 14:45:30 +0200730}
731
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100732static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200733{
734 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
735 struct sigmatel_spec *spec = codec->spec;
736 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
737
738 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
739 return 0;
740}
741
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100742static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Matt2f2f4252005-04-13 14:45:30 +0200743{
744 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
745 struct sigmatel_spec *spec = codec->spec;
746 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai5207e102009-07-30 13:09:08 +0200747 const struct hda_input_mux *imux = spec->input_mux;
Vitaliy Kulikov094a4242011-03-09 19:47:43 -0600748 unsigned int idx, prev_idx, didx;
Matt2f2f4252005-04-13 14:45:30 +0200749
Takashi Iwai5207e102009-07-30 13:09:08 +0200750 idx = ucontrol->value.enumerated.item[0];
751 if (idx >= imux->num_items)
752 idx = imux->num_items - 1;
753 prev_idx = spec->cur_mux[adc_idx];
754 if (prev_idx == idx)
755 return 0;
756 if (idx < spec->num_analog_muxes) {
757 snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0,
758 AC_VERB_SET_CONNECT_SEL,
759 imux->items[idx].index);
Vitaliy Kulikov094a4242011-03-09 19:47:43 -0600760 if (prev_idx >= spec->num_analog_muxes &&
761 spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) {
Takashi Iwai5207e102009-07-30 13:09:08 +0200762 imux = spec->dinput_mux;
763 /* 0 = analog */
764 snd_hda_codec_write_cache(codec,
765 spec->dmux_nids[adc_idx], 0,
766 AC_VERB_SET_CONNECT_SEL,
767 imux->items[0].index);
768 }
769 } else {
770 imux = spec->dinput_mux;
Vitaliy Kulikov094a4242011-03-09 19:47:43 -0600771 /* first dimux item is hardcoded to select analog imux,
772 * so lets skip it
773 */
774 didx = idx - spec->num_analog_muxes + 1;
Takashi Iwai5207e102009-07-30 13:09:08 +0200775 snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0,
776 AC_VERB_SET_CONNECT_SEL,
Vitaliy Kulikov094a4242011-03-09 19:47:43 -0600777 imux->items[didx].index);
Takashi Iwai5207e102009-07-30 13:09:08 +0200778 }
779 spec->cur_mux[adc_idx] = idx;
780 return 1;
Matt2f2f4252005-04-13 14:45:30 +0200781}
782
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100783static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
784 struct snd_ctl_elem_info *uinfo)
785{
786 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
787 struct sigmatel_spec *spec = codec->spec;
788 return snd_hda_input_mux_info(spec->mono_mux, uinfo);
789}
790
791static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
792 struct snd_ctl_elem_value *ucontrol)
793{
794 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
795 struct sigmatel_spec *spec = codec->spec;
796
797 ucontrol->value.enumerated.item[0] = spec->cur_mmux;
798 return 0;
799}
800
801static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
802 struct snd_ctl_elem_value *ucontrol)
803{
804 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
805 struct sigmatel_spec *spec = codec->spec;
806
807 return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
808 spec->mono_nid, &spec->cur_mmux);
809}
810
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200811#define stac92xx_aloopback_info snd_ctl_boolean_mono_info
812
813static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
814 struct snd_ctl_elem_value *ucontrol)
815{
816 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100817 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200818 struct sigmatel_spec *spec = codec->spec;
819
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100820 ucontrol->value.integer.value[0] = !!(spec->aloopback &
821 (spec->aloopback_mask << idx));
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200822 return 0;
823}
824
825static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
826 struct snd_ctl_elem_value *ucontrol)
827{
828 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
829 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100830 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200831 unsigned int dac_mode;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100832 unsigned int val, idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200833
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100834 idx_val = spec->aloopback_mask << idx;
835 if (ucontrol->value.integer.value[0])
836 val = spec->aloopback | idx_val;
837 else
838 val = spec->aloopback & ~idx_val;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100839 if (spec->aloopback == val)
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200840 return 0;
841
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100842 spec->aloopback = val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200843
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100844 /* Only return the bits defined by the shift value of the
845 * first two bytes of the mask
846 */
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200847 dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100848 kcontrol->private_value & 0xFFFF, 0x0);
849 dac_mode >>= spec->aloopback_shift;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200850
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100851 if (spec->aloopback & idx_val) {
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200852 snd_hda_power_up(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100853 dac_mode |= idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200854 } else {
855 snd_hda_power_down(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100856 dac_mode &= ~idx_val;
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200857 }
858
859 snd_hda_codec_write_cache(codec, codec->afg, 0,
860 kcontrol->private_value >> 16, dac_mode);
861
862 return 1;
863}
864
Takashi Iwai2b635362011-05-02 12:33:43 +0200865static const struct hda_verb stac9200_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200866 /* set dac0mux for dac converter */
Mattc7d4b2f2005-06-27 14:59:41 +0200867 { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Matt2f2f4252005-04-13 14:45:30 +0200868 {}
869};
870
Takashi Iwai2b635362011-05-02 12:33:43 +0200871static const struct hda_verb stac9200_eapd_init[] = {
Takashi Iwai1194b5b2007-10-10 10:04:26 +0200872 /* set dac0mux for dac converter */
873 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
874 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
875 {}
876};
877
Takashi Iwai2b635362011-05-02 12:33:43 +0200878static const struct hda_verb dell_eq_core_init[] = {
Matthew Ranostayd654a662008-03-14 08:46:51 +0100879 /* set master volume to max value without distortion
880 * and direct control */
881 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
Matthew Ranostayd654a662008-03-14 08:46:51 +0100882 {}
883};
884
Takashi Iwai2b635362011-05-02 12:33:43 +0200885static const struct hda_verb stac92hd73xx_core_init[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100886 /* set master volume and direct control */
887 { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100888 {}
889};
890
Takashi Iwai2b635362011-05-02 12:33:43 +0200891static const struct hda_verb stac92hd83xxx_core_init[] = {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200892 /* power state controls amps */
893 { 0x01, AC_VERB_SET_EAPD, 1 << 2},
Herton Ronaldo Krzesinski574f3c42008-12-23 16:53:00 -0200894 {}
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200895};
896
Vitaliy Kulikov5556e142012-02-27 16:47:37 -0600897static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
898 { 0x22, 0x785, 0x43 },
899 { 0x22, 0x782, 0xe0 },
900 { 0x22, 0x795, 0x00 },
901 {}
902};
903
Takashi Iwai2b635362011-05-02 12:33:43 +0200904static const struct hda_verb stac92hd71bxx_core_init[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +0100905 /* set master volume and direct control */
906 { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Herton Ronaldo Krzesinski574f3c42008-12-23 16:53:00 -0200907 {}
Matthew Ranostay541eee82007-12-14 12:08:04 +0100908};
909
Takashi Iwai2b635362011-05-02 12:33:43 +0200910static const struct hda_verb stac92hd71bxx_unmute_core_init[] = {
Matthew Ranostayca8d33f2009-01-26 09:33:52 -0500911 /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
912 { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100913 { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
914 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Matthew Ranostaye035b842007-11-06 11:53:55 +0100915 {}
916};
917
Takashi Iwai2b635362011-05-02 12:33:43 +0200918static const struct hda_verb stac925x_core_init[] = {
Tobin Davis8e21c342007-01-08 11:04:17 +0100919 /* set dac0mux for dac converter */
920 { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaic9280d62009-01-15 17:31:00 +0100921 /* mute the master volume */
922 { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Tobin Davis8e21c342007-01-08 11:04:17 +0100923 {}
924};
925
Takashi Iwai2b635362011-05-02 12:33:43 +0200926static const struct hda_verb stac922x_core_init[] = {
Matt2f2f4252005-04-13 14:45:30 +0200927 /* set master volume and direct control */
Mattc7d4b2f2005-06-27 14:59:41 +0200928 { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matt2f2f4252005-04-13 14:45:30 +0200929 {}
930};
931
Takashi Iwai2b635362011-05-02 12:33:43 +0200932static const struct hda_verb d965_core_init[] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +0200933 /* set master volume and direct control */
Tobin Davis93ed1502006-09-01 21:03:12 +0200934 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Takashi Iwai19039bd2006-06-28 15:52:16 +0200935 /* unmute node 0x1b */
936 { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
937 /* select node 0x03 as DAC */
938 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
939 {}
940};
941
Takashi Iwai2b635362011-05-02 12:33:43 +0200942static const struct hda_verb dell_3st_core_init[] = {
Takashi Iwaiccca7cd2009-10-13 15:32:21 +0200943 /* don't set delta bit */
944 {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
945 /* unmute node 0x1b */
946 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
947 /* select node 0x03 as DAC */
948 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
949 {}
950};
951
Takashi Iwai2b635362011-05-02 12:33:43 +0200952static const struct hda_verb stac927x_core_init[] = {
Matt Porter3cc08dc2006-01-23 15:27:49 +0100953 /* set master volume and direct control */
954 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostay1cd22242008-07-18 18:20:52 +0200955 /* enable analog pc beep path */
956 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porter3cc08dc2006-01-23 15:27:49 +0100957 {}
958};
959
Takashi Iwai2b635362011-05-02 12:33:43 +0200960static const struct hda_verb stac927x_volknob_core_init[] = {
Takashi Iwai54930532009-10-11 17:38:29 +0200961 /* don't set delta bit */
962 {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
963 /* enable analog pc beep path */
964 {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
965 {}
966};
967
Takashi Iwai2b635362011-05-02 12:33:43 +0200968static const struct hda_verb stac9205_core_init[] = {
Matt Porterf3302a52006-07-31 12:49:34 +0200969 /* set master volume and direct control */
970 { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +0200971 /* enable analog pc beep path */
972 { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
Matt Porterf3302a52006-07-31 12:49:34 +0200973 {}
974};
975
Matthew Ranostayb22b4822008-01-22 12:32:30 +0100976#define STAC_MONO_MUX \
977 { \
978 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
979 .name = "Mono Mux", \
980 .count = 1, \
981 .info = stac92xx_mono_mux_enum_info, \
982 .get = stac92xx_mono_mux_enum_get, \
983 .put = stac92xx_mono_mux_enum_put, \
984 }
985
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100986#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200987 { \
988 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
989 .name = "Analog Loopback", \
Matthew Ranostaye1f0d662007-12-13 17:47:21 +0100990 .count = cnt, \
Maxim Levitsky5f10c4a2007-09-03 15:29:37 +0200991 .info = stac92xx_aloopback_info, \
992 .get = stac92xx_aloopback_get, \
993 .put = stac92xx_aloopback_put, \
994 .private_value = verb_read | (verb_write << 16), \
995 }
996
Nickolas Lloyd2fc99892009-05-15 15:33:30 +0200997#define DC_BIAS(xname, idx, nid) \
998 { \
999 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1000 .name = xname, \
1001 .index = idx, \
1002 .info = stac92xx_dc_bias_info, \
1003 .get = stac92xx_dc_bias_get, \
1004 .put = stac92xx_dc_bias_put, \
1005 .private_value = nid, \
1006 }
1007
Takashi Iwai2b635362011-05-02 12:33:43 +02001008static const struct snd_kcontrol_new stac9200_mixer[] = {
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01001009 HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT),
1010 HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +02001011 HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
1012 HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
Matt2f2f4252005-04-13 14:45:30 +02001013 { } /* end */
1014};
1015
Takashi Iwai2b635362011-05-02 12:33:43 +02001016static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = {
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001017 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
1018 {}
1019};
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001020
Takashi Iwai2b635362011-05-02 12:33:43 +02001021static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = {
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001022 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
1023 {}
1024};
1025
Takashi Iwai2b635362011-05-02 12:33:43 +02001026static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = {
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001027 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
1028 {}
1029};
1030
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001031
Takashi Iwai2b635362011-05-02 12:33:43 +02001032static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001033 STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2)
1034};
Matthew Ranostay541eee82007-12-14 12:08:04 +01001035
Takashi Iwai2b635362011-05-02 12:33:43 +02001036static const struct snd_kcontrol_new stac925x_mixer[] = {
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01001037 HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT),
1038 HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT),
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02001039 { } /* end */
1040};
1041
Takashi Iwai2b635362011-05-02 12:33:43 +02001042static const struct snd_kcontrol_new stac9205_loopback[] = {
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001043 STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
1044 {}
1045};
1046
Takashi Iwai2b635362011-05-02 12:33:43 +02001047static const struct snd_kcontrol_new stac927x_loopback[] = {
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001048 STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
1049 {}
1050};
1051
Takashi Iwai1697055e2007-12-18 18:05:52 +01001052static struct snd_kcontrol_new stac_dmux_mixer = {
1053 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1054 .name = "Digital Input Source",
1055 /* count set later */
1056 .info = stac92xx_dmux_enum_info,
1057 .get = stac92xx_dmux_enum_get,
1058 .put = stac92xx_dmux_enum_put,
1059};
1060
Matthew Ranostayd9737752008-09-07 12:03:41 +02001061static struct snd_kcontrol_new stac_smux_mixer = {
1062 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Matthew Ranostaye3487972008-09-08 11:36:59 -04001063 .name = "IEC958 Playback Source",
Matthew Ranostayd9737752008-09-07 12:03:41 +02001064 /* count set later */
1065 .info = stac92xx_smux_enum_info,
1066 .get = stac92xx_smux_enum_get,
1067 .put = stac92xx_smux_enum_put,
1068};
1069
Takashi Iwai9322ca52012-02-03 14:28:01 +01001070static const char * const slave_pfxs[] = {
1071 "Front", "Surround", "Center", "LFE", "Side",
Takashi Iwaif37bc7a2012-11-08 15:59:23 +01001072 "Headphone", "Speaker", "Bass Speaker", "IEC958", "PCM",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001073 NULL
1074};
1075
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01001076static void stac92xx_update_led_status(struct hda_codec *codec, int enabled);
1077
1078static void stac92xx_vmaster_hook(void *private_data, int val)
1079{
1080 stac92xx_update_led_status(private_data, val);
1081}
1082
Takashi Iwai603c4012008-07-30 15:01:44 +02001083static void stac92xx_free_kctls(struct hda_codec *codec);
1084
Matt2f2f4252005-04-13 14:45:30 +02001085static int stac92xx_build_controls(struct hda_codec *codec)
1086{
1087 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01001088 unsigned int vmaster_tlv[4];
Matt2f2f4252005-04-13 14:45:30 +02001089 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02001090 int i;
Matt2f2f4252005-04-13 14:45:30 +02001091
Takashi Iwai6479c632009-07-28 18:20:25 +02001092 if (spec->mixer) {
1093 err = snd_hda_add_new_ctls(codec, spec->mixer);
1094 if (err < 0)
1095 return err;
1096 }
Mattc7d4b2f2005-06-27 14:59:41 +02001097
1098 for (i = 0; i < spec->num_mixers; i++) {
1099 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1100 if (err < 0)
1101 return err;
1102 }
Takashi Iwai5207e102009-07-30 13:09:08 +02001103 if (!spec->auto_mic && spec->num_dmuxes > 0 &&
1104 snd_hda_get_bool_hint(codec, "separate_dmux") == 1) {
Takashi Iwai1697055e2007-12-18 18:05:52 +01001105 stac_dmux_mixer.count = spec->num_dmuxes;
Jaroslav Kysela3911a4c2009-11-11 13:43:01 +01001106 err = snd_hda_ctl_add(codec, 0,
Takashi Iwai1697055e2007-12-18 18:05:52 +01001107 snd_ctl_new1(&stac_dmux_mixer, codec));
1108 if (err < 0)
1109 return err;
1110 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001111 if (spec->num_smuxes > 0) {
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001112 int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid);
1113 struct hda_input_mux *smux = &spec->private_smux;
1114 /* check for mute support on SPDIF out */
1115 if (wcaps & AC_WCAP_OUT_AMP) {
Takashi Iwai10a20af2010-09-09 16:28:02 +02001116 snd_hda_add_imux_item(smux, "Off", 0, NULL);
Matthew Ranostay00ef50c2008-09-27 18:13:47 -04001117 spec->spdif_mute = 1;
1118 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02001119 stac_smux_mixer.count = spec->num_smuxes;
Jaroslav Kysela3911a4c2009-11-11 13:43:01 +01001120 err = snd_hda_ctl_add(codec, 0,
Matthew Ranostayd9737752008-09-07 12:03:41 +02001121 snd_ctl_new1(&stac_smux_mixer, codec));
1122 if (err < 0)
1123 return err;
1124 }
Mattc7d4b2f2005-06-27 14:59:41 +02001125
Mattdabbed62005-06-14 10:19:34 +02001126 if (spec->multiout.dig_out_nid) {
Takashi Iwaidcda5802012-10-12 17:24:51 +02001127 err = snd_hda_create_dig_out_ctls(codec,
1128 spec->multiout.dig_out_nid,
1129 spec->multiout.dig_out_nid,
1130 spec->autocfg.dig_out_type[0]);
Mattdabbed62005-06-14 10:19:34 +02001131 if (err < 0)
1132 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001133 err = snd_hda_create_spdif_share_sw(codec,
1134 &spec->multiout);
1135 if (err < 0)
1136 return err;
1137 spec->multiout.share_spdif = 1;
Mattdabbed62005-06-14 10:19:34 +02001138 }
Harvey Harrisonda74ae32008-10-21 20:28:04 -07001139 if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) {
Mattdabbed62005-06-14 10:19:34 +02001140 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1141 if (err < 0)
1142 return err;
1143 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001144
1145 /* if we have no master control, let's create it */
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01001146 snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
1147 HDA_OUTPUT, vmaster_tlv);
1148 /* correct volume offset */
1149 vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
1150 /* minimum value is actually mute */
1151 vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
1152 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
1153 vmaster_tlv, slave_pfxs,
1154 "Playback Volume");
1155 if (err < 0)
1156 return err;
1157
1158 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
1159 NULL, slave_pfxs,
1160 "Playback Switch", true,
Takashi Iwaid2f344b2012-03-12 16:59:58 +01001161 &spec->vmaster_mute.sw_kctl);
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01001162 if (err < 0)
1163 return err;
1164
1165 if (spec->gpio_led) {
Takashi Iwaid2f344b2012-03-12 16:59:58 +01001166 spec->vmaster_mute.hook = stac92xx_vmaster_hook;
Takashi Iwaif29735c2012-03-13 07:55:10 +01001167 err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
Takashi Iwaid2f344b2012-03-12 16:59:58 +01001168 if (err < 0)
1169 return err;
Takashi Iwai2134ea42008-01-10 16:53:55 +01001170 }
1171
Takashi Iwaid78d7a92009-03-02 14:26:25 +01001172 if (spec->aloopback_ctl &&
1173 snd_hda_get_bool_hint(codec, "loopback") == 1) {
1174 err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl);
1175 if (err < 0)
1176 return err;
1177 }
1178
Takashi Iwai603c4012008-07-30 15:01:44 +02001179 stac92xx_free_kctls(codec); /* no longer needed */
Takashi Iwaie4973e12008-11-18 09:32:42 +01001180
Takashi Iwai01a61e12011-10-28 00:03:22 +02001181 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
1182 if (err < 0)
1183 return err;
Takashi Iwaie4973e12008-11-18 09:32:42 +01001184
Mattdabbed62005-06-14 10:19:34 +02001185 return 0;
Matt2f2f4252005-04-13 14:45:30 +02001186}
1187
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001188static const struct hda_pintbl ref9200_pin_configs[] = {
1189 { 0x08, 0x01c47010 },
1190 { 0x09, 0x01447010 },
1191 { 0x0d, 0x0221401f },
1192 { 0x0e, 0x01114010 },
1193 { 0x0f, 0x02a19020 },
1194 { 0x10, 0x01a19021 },
1195 { 0x11, 0x90100140 },
1196 { 0x12, 0x01813122 },
1197 {}
Matt2f2f4252005-04-13 14:45:30 +02001198};
1199
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001200static const struct hda_pintbl gateway9200_m4_pin_configs[] = {
1201 { 0x08, 0x400000fe },
1202 { 0x09, 0x404500f4 },
1203 { 0x0d, 0x400100f0 },
1204 { 0x0e, 0x90110010 },
1205 { 0x0f, 0x400100f1 },
1206 { 0x10, 0x02a1902e },
1207 { 0x11, 0x500000f2 },
1208 { 0x12, 0x500000f3 },
1209 {}
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001210};
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001211
1212static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = {
1213 { 0x08, 0x400000fe },
1214 { 0x09, 0x404500f4 },
1215 { 0x0d, 0x400100f0 },
1216 { 0x0e, 0x90110010 },
1217 { 0x0f, 0x400100f1 },
1218 { 0x10, 0x02a1902e },
1219 { 0x11, 0x500000f2 },
1220 { 0x12, 0x500000f3 },
1221 {}
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001222};
1223
1224/*
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001225 STAC 9200 pin configs for
1226 102801A8
1227 102801DE
1228 102801E8
1229*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001230static const struct hda_pintbl dell9200_d21_pin_configs[] = {
1231 { 0x08, 0x400001f0 },
1232 { 0x09, 0x400001f1 },
1233 { 0x0d, 0x02214030 },
1234 { 0x0e, 0x01014010 },
1235 { 0x0f, 0x02a19020 },
1236 { 0x10, 0x01a19021 },
1237 { 0x11, 0x90100140 },
1238 { 0x12, 0x01813122 },
1239 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001240};
1241
1242/*
1243 STAC 9200 pin configs for
1244 102801C0
1245 102801C1
1246*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001247static const struct hda_pintbl dell9200_d22_pin_configs[] = {
1248 { 0x08, 0x400001f0 },
1249 { 0x09, 0x400001f1 },
1250 { 0x0d, 0x0221401f },
1251 { 0x0e, 0x01014010 },
1252 { 0x0f, 0x01813020 },
1253 { 0x10, 0x02a19021 },
1254 { 0x11, 0x90100140 },
1255 { 0x12, 0x400001f2 },
1256 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001257};
1258
1259/*
1260 STAC 9200 pin configs for
1261 102801C4 (Dell Dimension E310)
1262 102801C5
1263 102801C7
1264 102801D9
1265 102801DA
1266 102801E3
1267*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001268static const struct hda_pintbl dell9200_d23_pin_configs[] = {
1269 { 0x08, 0x400001f0 },
1270 { 0x09, 0x400001f1 },
1271 { 0x0d, 0x0221401f },
1272 { 0x0e, 0x01014010 },
1273 { 0x0f, 0x01813020 },
1274 { 0x10, 0x01a19021 },
1275 { 0x11, 0x90100140 },
1276 { 0x12, 0x400001f2 },
1277 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001278};
1279
1280
1281/*
1282 STAC 9200-32 pin configs for
1283 102801B5 (Dell Inspiron 630m)
1284 102801D8 (Dell Inspiron 640m)
1285*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001286static const struct hda_pintbl dell9200_m21_pin_configs[] = {
1287 { 0x08, 0x40c003fa },
1288 { 0x09, 0x03441340 },
1289 { 0x0d, 0x0321121f },
1290 { 0x0e, 0x90170310 },
1291 { 0x0f, 0x408003fb },
1292 { 0x10, 0x03a11020 },
1293 { 0x11, 0x401003fc },
1294 { 0x12, 0x403003fd },
1295 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001296};
1297
1298/*
1299 STAC 9200-32 pin configs for
1300 102801C2 (Dell Latitude D620)
1301 102801C8
1302 102801CC (Dell Latitude D820)
1303 102801D4
1304 102801D6
1305*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001306static const struct hda_pintbl dell9200_m22_pin_configs[] = {
1307 { 0x08, 0x40c003fa },
1308 { 0x09, 0x0144131f },
1309 { 0x0d, 0x0321121f },
1310 { 0x0e, 0x90170310 },
1311 { 0x0f, 0x90a70321 },
1312 { 0x10, 0x03a11020 },
1313 { 0x11, 0x401003fb },
1314 { 0x12, 0x40f000fc },
1315 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001316};
1317
1318/*
1319 STAC 9200-32 pin configs for
1320 102801CE (Dell XPS M1710)
1321 102801CF (Dell Precision M90)
1322*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001323static const struct hda_pintbl dell9200_m23_pin_configs[] = {
1324 { 0x08, 0x40c003fa },
1325 { 0x09, 0x01441340 },
1326 { 0x0d, 0x0421421f },
1327 { 0x0e, 0x90170310 },
1328 { 0x0f, 0x408003fb },
1329 { 0x10, 0x04a1102e },
1330 { 0x11, 0x90170311 },
1331 { 0x12, 0x403003fc },
1332 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001333};
1334
1335/*
1336 STAC 9200-32 pin configs for
1337 102801C9
1338 102801CA
1339 102801CB (Dell Latitude 120L)
1340 102801D3
1341*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001342static const struct hda_pintbl dell9200_m24_pin_configs[] = {
1343 { 0x08, 0x40c003fa },
1344 { 0x09, 0x404003fb },
1345 { 0x0d, 0x0321121f },
1346 { 0x0e, 0x90170310 },
1347 { 0x0f, 0x408003fc },
1348 { 0x10, 0x03a11020 },
1349 { 0x11, 0x401003fd },
1350 { 0x12, 0x403003fe },
1351 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001352};
1353
1354/*
1355 STAC 9200-32 pin configs for
1356 102801BD (Dell Inspiron E1505n)
1357 102801EE
1358 102801EF
1359*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001360static const struct hda_pintbl dell9200_m25_pin_configs[] = {
1361 { 0x08, 0x40c003fa },
1362 { 0x09, 0x01441340 },
1363 { 0x0d, 0x0421121f },
1364 { 0x0e, 0x90170310 },
1365 { 0x0f, 0x408003fb },
1366 { 0x10, 0x04a11020 },
1367 { 0x11, 0x401003fc },
1368 { 0x12, 0x403003fd },
1369 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001370};
1371
1372/*
1373 STAC 9200-32 pin configs for
1374 102801F5 (Dell Inspiron 1501)
1375 102801F6
1376*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001377static const struct hda_pintbl dell9200_m26_pin_configs[] = {
1378 { 0x08, 0x40c003fa },
1379 { 0x09, 0x404003fb },
1380 { 0x0d, 0x0421121f },
1381 { 0x0e, 0x90170310 },
1382 { 0x0f, 0x408003fc },
1383 { 0x10, 0x04a11020 },
1384 { 0x11, 0x401003fd },
1385 { 0x12, 0x403003fe },
1386 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001387};
1388
1389/*
1390 STAC 9200-32
1391 102801CD (Dell Inspiron E1705/9400)
1392*/
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001393static const struct hda_pintbl dell9200_m27_pin_configs[] = {
1394 { 0x08, 0x40c003fa },
1395 { 0x09, 0x01441340 },
1396 { 0x0d, 0x0421121f },
1397 { 0x0e, 0x90170310 },
1398 { 0x0f, 0x90170310 },
1399 { 0x10, 0x04a11020 },
1400 { 0x11, 0x90170310 },
1401 { 0x12, 0x40f003fc },
1402 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001403};
1404
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001405static const struct hda_pintbl oqo9200_pin_configs[] = {
1406 { 0x08, 0x40c000f0 },
1407 { 0x09, 0x404000f1 },
1408 { 0x0d, 0x0221121f },
1409 { 0x0e, 0x02211210 },
1410 { 0x0f, 0x90170111 },
1411 { 0x10, 0x90a70120 },
1412 { 0x11, 0x400000f2 },
1413 { 0x12, 0x400000f3 },
1414 {}
Tobin Davisbf277782008-02-03 20:31:47 +01001415};
1416
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001417
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001418static void stac9200_fixup_panasonic(struct hda_codec *codec,
1419 const struct hda_fixup *fix, int action)
1420{
1421 struct sigmatel_spec *spec = codec->spec;
1422
1423 switch (action) {
1424 case HDA_FIXUP_ACT_PRE_PROBE:
1425 spec->gpio_mask = spec->gpio_dir = 0x09;
1426 spec->gpio_data = 0x00;
1427 break;
1428 case HDA_FIXUP_ACT_PROBE:
1429 /* CF-74 has no headphone detection, and the driver should *NOT*
1430 * do detection and HP/speaker toggle because the hardware does it.
1431 */
1432 spec->hp_detect = 0;
1433 break;
1434 }
1435}
1436
1437
1438static const struct hda_fixup stac9200_fixups[] = {
1439 [STAC_REF] = {
1440 .type = HDA_FIXUP_PINS,
1441 .v.pins = ref9200_pin_configs,
1442 },
1443 [STAC_9200_OQO] = {
1444 .type = HDA_FIXUP_PINS,
1445 .v.pins = oqo9200_pin_configs,
1446 .chained = true,
1447 .chain_id = STAC_9200_EAPD_INIT,
1448 },
1449 [STAC_9200_DELL_D21] = {
1450 .type = HDA_FIXUP_PINS,
1451 .v.pins = dell9200_d21_pin_configs,
1452 },
1453 [STAC_9200_DELL_D22] = {
1454 .type = HDA_FIXUP_PINS,
1455 .v.pins = dell9200_d22_pin_configs,
1456 },
1457 [STAC_9200_DELL_D23] = {
1458 .type = HDA_FIXUP_PINS,
1459 .v.pins = dell9200_d23_pin_configs,
1460 },
1461 [STAC_9200_DELL_M21] = {
1462 .type = HDA_FIXUP_PINS,
1463 .v.pins = dell9200_m21_pin_configs,
1464 },
1465 [STAC_9200_DELL_M22] = {
1466 .type = HDA_FIXUP_PINS,
1467 .v.pins = dell9200_m22_pin_configs,
1468 },
1469 [STAC_9200_DELL_M23] = {
1470 .type = HDA_FIXUP_PINS,
1471 .v.pins = dell9200_m23_pin_configs,
1472 },
1473 [STAC_9200_DELL_M24] = {
1474 .type = HDA_FIXUP_PINS,
1475 .v.pins = dell9200_m24_pin_configs,
1476 },
1477 [STAC_9200_DELL_M25] = {
1478 .type = HDA_FIXUP_PINS,
1479 .v.pins = dell9200_m25_pin_configs,
1480 },
1481 [STAC_9200_DELL_M26] = {
1482 .type = HDA_FIXUP_PINS,
1483 .v.pins = dell9200_m26_pin_configs,
1484 },
1485 [STAC_9200_DELL_M27] = {
1486 .type = HDA_FIXUP_PINS,
1487 .v.pins = dell9200_m27_pin_configs,
1488 },
1489 [STAC_9200_M4] = {
1490 .type = HDA_FIXUP_PINS,
1491 .v.pins = gateway9200_m4_pin_configs,
1492 .chained = true,
1493 .chain_id = STAC_9200_EAPD_INIT,
1494 },
1495 [STAC_9200_M4_2] = {
1496 .type = HDA_FIXUP_PINS,
1497 .v.pins = gateway9200_m4_2_pin_configs,
1498 .chained = true,
1499 .chain_id = STAC_9200_EAPD_INIT,
1500 },
1501 [STAC_9200_PANASONIC] = {
1502 .type = HDA_FIXUP_FUNC,
1503 .v.func = stac9200_fixup_panasonic,
1504 },
1505 [STAC_9200_EAPD_INIT] = {
1506 .type = HDA_FIXUP_VERBS,
1507 .v.verbs = (const struct hda_verb[]) {
1508 {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
1509 {}
1510 },
1511 },
Matt Porter403d1942005-11-29 15:00:51 +01001512};
1513
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001514static const struct hda_model_fixup stac9200_models[] = {
1515 { .id = STAC_REF, .name = "ref" },
1516 { .id = STAC_9200_OQO, .name = "oqo" },
1517 { .id = STAC_9200_DELL_D21, .name = "dell-d21" },
1518 { .id = STAC_9200_DELL_D22, .name = "dell-d22" },
1519 { .id = STAC_9200_DELL_D23, .name = "dell-d23" },
1520 { .id = STAC_9200_DELL_M21, .name = "dell-m21" },
1521 { .id = STAC_9200_DELL_M22, .name = "dell-m22" },
1522 { .id = STAC_9200_DELL_M23, .name = "dell-m23" },
1523 { .id = STAC_9200_DELL_M24, .name = "dell-m24" },
1524 { .id = STAC_9200_DELL_M25, .name = "dell-m25" },
1525 { .id = STAC_9200_DELL_M26, .name = "dell-m26" },
1526 { .id = STAC_9200_DELL_M27, .name = "dell-m27" },
1527 { .id = STAC_9200_M4, .name = "gateway-m4" },
1528 { .id = STAC_9200_M4_2, .name = "gateway-m4-2" },
1529 { .id = STAC_9200_PANASONIC, .name = "panasonic" },
1530 {}
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001531};
1532
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01001533static const struct snd_pci_quirk stac9200_fixup_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001534 /* SigmaTel reference board */
1535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
1536 "DFI LanParty", STAC_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05001537 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
1538 "DFI LanParty", STAC_REF),
Matt Portere7377072006-11-06 11:20:38 +01001539 /* Dell laptops have BIOS problem */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001540 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
1541 "unknown Dell", STAC_9200_DELL_D21),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001542 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001543 "Dell Inspiron 630m", STAC_9200_DELL_M21),
1544 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
1545 "Dell Inspiron E1505n", STAC_9200_DELL_M25),
1546 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
1547 "unknown Dell", STAC_9200_DELL_D22),
1548 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
1549 "unknown Dell", STAC_9200_DELL_D22),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001550 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001551 "Dell Latitude D620", STAC_9200_DELL_M22),
1552 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
1553 "unknown Dell", STAC_9200_DELL_D23),
1554 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
1555 "unknown Dell", STAC_9200_DELL_D23),
1556 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
1557 "unknown Dell", STAC_9200_DELL_M22),
1558 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
1559 "unknown Dell", STAC_9200_DELL_M24),
1560 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
1561 "unknown Dell", STAC_9200_DELL_M24),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001562 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001563 "Dell Latitude 120L", STAC_9200_DELL_M24),
Cory T. Tusar877b8662007-01-30 17:30:55 +01001564 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001565 "Dell Latitude D820", STAC_9200_DELL_M22),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001566 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001567 "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
Mikael Nilsson46f02ca2007-02-13 12:46:16 +01001568 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001569 "Dell XPS M1710", STAC_9200_DELL_M23),
Takashi Iwaif0f96742007-02-14 00:59:17 +01001570 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001571 "Dell Precision M90", STAC_9200_DELL_M23),
1572 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
1573 "unknown Dell", STAC_9200_DELL_M22),
1574 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
1575 "unknown Dell", STAC_9200_DELL_M22),
Daniel T Chen8286c532007-05-15 11:46:23 +02001576 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001577 "unknown Dell", STAC_9200_DELL_M22),
Tobin Davis49c605d2007-05-17 09:38:24 +02001578 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001579 "Dell Inspiron 640m", STAC_9200_DELL_M21),
1580 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
1581 "unknown Dell", STAC_9200_DELL_D23),
1582 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
1583 "unknown Dell", STAC_9200_DELL_D23),
1584 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
1585 "unknown Dell", STAC_9200_DELL_D21),
1586 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
1587 "unknown Dell", STAC_9200_DELL_D23),
1588 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
1589 "unknown Dell", STAC_9200_DELL_D21),
1590 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
1591 "unknown Dell", STAC_9200_DELL_M25),
1592 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
1593 "unknown Dell", STAC_9200_DELL_M25),
Tobin Davis49c605d2007-05-17 09:38:24 +02001594 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02001595 "Dell Inspiron 1501", STAC_9200_DELL_M26),
1596 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
1597 "unknown Dell", STAC_9200_DELL_M26),
Tobin Davis49c605d2007-05-17 09:38:24 +02001598 /* Panasonic */
Takashi Iwai117f2572008-03-18 09:53:23 +01001599 SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
Takashi Iwai1194b5b2007-10-10 10:04:26 +02001600 /* Gateway machines needs EAPD to be set on resume */
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001601 SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
1602 SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
1603 SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
Tobin Davisbf277782008-02-03 20:31:47 +01001604 /* OQO Mobile */
1605 SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
Matt Porter403d1942005-11-29 15:00:51 +01001606 {} /* terminator */
1607};
1608
Takashi Iwaid2077d42013-01-14 14:20:16 +01001609static const struct hda_pintbl ref925x_pin_configs[] = {
1610 { 0x07, 0x40c003f0 },
1611 { 0x08, 0x424503f2 },
1612 { 0x0a, 0x01813022 },
1613 { 0x0b, 0x02a19021 },
1614 { 0x0c, 0x90a70320 },
1615 { 0x0d, 0x02214210 },
1616 { 0x10, 0x01019020 },
1617 { 0x11, 0x9033032e },
1618 {}
Tobin Davis8e21c342007-01-08 11:04:17 +01001619};
1620
Takashi Iwaid2077d42013-01-14 14:20:16 +01001621static const struct hda_pintbl stac925xM1_pin_configs[] = {
1622 { 0x07, 0x40c003f4 },
1623 { 0x08, 0x424503f2 },
1624 { 0x0a, 0x400000f3 },
1625 { 0x0b, 0x02a19020 },
1626 { 0x0c, 0x40a000f0 },
1627 { 0x0d, 0x90100210 },
1628 { 0x10, 0x400003f1 },
1629 { 0x11, 0x9033032e },
1630 {}
Tobin Davis8e21c342007-01-08 11:04:17 +01001631};
1632
Takashi Iwaid2077d42013-01-14 14:20:16 +01001633static const struct hda_pintbl stac925xM1_2_pin_configs[] = {
1634 { 0x07, 0x40c003f4 },
1635 { 0x08, 0x424503f2 },
1636 { 0x0a, 0x400000f3 },
1637 { 0x0b, 0x02a19020 },
1638 { 0x0c, 0x40a000f0 },
1639 { 0x0d, 0x90100210 },
1640 { 0x10, 0x400003f1 },
1641 { 0x11, 0x9033032e },
1642 {}
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02001643};
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001644
Takashi Iwaid2077d42013-01-14 14:20:16 +01001645static const struct hda_pintbl stac925xM2_pin_configs[] = {
1646 { 0x07, 0x40c003f4 },
1647 { 0x08, 0x424503f2 },
1648 { 0x0a, 0x400000f3 },
1649 { 0x0b, 0x02a19020 },
1650 { 0x0c, 0x40a000f0 },
1651 { 0x0d, 0x90100210 },
1652 { 0x10, 0x400003f1 },
1653 { 0x11, 0x9033032e },
1654 {}
Tobin Davis2c11f952007-05-17 09:36:34 +02001655};
1656
Takashi Iwaid2077d42013-01-14 14:20:16 +01001657static const struct hda_pintbl stac925xM2_2_pin_configs[] = {
1658 { 0x07, 0x40c003f4 },
1659 { 0x08, 0x424503f2 },
1660 { 0x0a, 0x400000f3 },
1661 { 0x0b, 0x02a19020 },
1662 { 0x0c, 0x40a000f0 },
1663 { 0x0d, 0x90100210 },
1664 { 0x10, 0x400003f1 },
1665 { 0x11, 0x9033032e },
1666 {}
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001667};
1668
Takashi Iwaid2077d42013-01-14 14:20:16 +01001669static const struct hda_pintbl stac925xM3_pin_configs[] = {
1670 { 0x07, 0x40c003f4 },
1671 { 0x08, 0x424503f2 },
1672 { 0x0a, 0x400000f3 },
1673 { 0x0b, 0x02a19020 },
1674 { 0x0c, 0x40a000f0 },
1675 { 0x0d, 0x90100210 },
1676 { 0x10, 0x400003f1 },
1677 { 0x11, 0x503303f3 },
1678 {}
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02001679};
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001680
Takashi Iwaid2077d42013-01-14 14:20:16 +01001681static const struct hda_pintbl stac925xM5_pin_configs[] = {
1682 { 0x07, 0x40c003f4 },
1683 { 0x08, 0x424503f2 },
1684 { 0x0a, 0x400000f3 },
1685 { 0x0b, 0x02a19020 },
1686 { 0x0c, 0x40a000f0 },
1687 { 0x0d, 0x90100210 },
1688 { 0x10, 0x400003f1 },
1689 { 0x11, 0x9033032e },
1690 {}
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02001691};
1692
Takashi Iwaid2077d42013-01-14 14:20:16 +01001693static const struct hda_pintbl stac925xM6_pin_configs[] = {
1694 { 0x07, 0x40c003f4 },
1695 { 0x08, 0x424503f2 },
1696 { 0x0a, 0x400000f3 },
1697 { 0x0b, 0x02a19020 },
1698 { 0x0c, 0x40a000f0 },
1699 { 0x0d, 0x90100210 },
1700 { 0x10, 0x400003f1 },
1701 { 0x11, 0x90330320 },
1702 {}
Tobin Davis8e21c342007-01-08 11:04:17 +01001703};
1704
Takashi Iwaid2077d42013-01-14 14:20:16 +01001705static const struct hda_fixup stac925x_fixups[] = {
1706 [STAC_REF] = {
1707 .type = HDA_FIXUP_PINS,
1708 .v.pins = ref925x_pin_configs,
1709 },
1710 [STAC_M1] = {
1711 .type = HDA_FIXUP_PINS,
1712 .v.pins = stac925xM1_pin_configs,
1713 },
1714 [STAC_M1_2] = {
1715 .type = HDA_FIXUP_PINS,
1716 .v.pins = stac925xM1_2_pin_configs,
1717 },
1718 [STAC_M2] = {
1719 .type = HDA_FIXUP_PINS,
1720 .v.pins = stac925xM2_pin_configs,
1721 },
1722 [STAC_M2_2] = {
1723 .type = HDA_FIXUP_PINS,
1724 .v.pins = stac925xM2_2_pin_configs,
1725 },
1726 [STAC_M3] = {
1727 .type = HDA_FIXUP_PINS,
1728 .v.pins = stac925xM3_pin_configs,
1729 },
1730 [STAC_M5] = {
1731 .type = HDA_FIXUP_PINS,
1732 .v.pins = stac925xM5_pin_configs,
1733 },
1734 [STAC_M6] = {
1735 .type = HDA_FIXUP_PINS,
1736 .v.pins = stac925xM6_pin_configs,
1737 },
Tobin Davis8e21c342007-01-08 11:04:17 +01001738};
1739
Takashi Iwaid2077d42013-01-14 14:20:16 +01001740static const struct hda_model_fixup stac925x_models[] = {
1741 { .id = STAC_REF, .name = "ref" },
1742 { .id = STAC_M1, .name = "m1" },
1743 { .id = STAC_M1_2, .name = "m1-2" },
1744 { .id = STAC_M2, .name = "m2" },
1745 { .id = STAC_M2_2, .name = "m2-2" },
1746 { .id = STAC_M3, .name = "m3" },
1747 { .id = STAC_M5, .name = "m5" },
1748 { .id = STAC_M6, .name = "m6" },
1749 {}
Tobin Davis8e21c342007-01-08 11:04:17 +01001750};
1751
Takashi Iwaid2077d42013-01-14 14:20:16 +01001752static const struct snd_pci_quirk stac925x_fixup_tbl[] = {
1753 /* SigmaTel reference board */
1754 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
1755 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
1756 SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
1757
1758 /* Default table for unknown ID */
1759 SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
1760
1761 /* gateway machines are checked via codec ssid */
Mauro Carvalho Chehab58eec422008-08-11 10:18:39 +02001762 SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
1763 SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
1764 SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
1765 SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02001766 SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02001767 /* Not sure about the brand name for those */
1768 SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
1769 SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
1770 SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
1771 SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02001772 {} /* terminator */
Tobin Davis8e21c342007-01-08 11:04:17 +01001773};
1774
Takashi Iwai2b635362011-05-02 12:33:43 +02001775static const unsigned int ref92hd73xx_pin_configs[13] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001776 0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
1777 0x0181302e, 0x01014010, 0x01014020, 0x01014030,
1778 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001779 0x01452050,
1780};
1781
Takashi Iwai2b635362011-05-02 12:33:43 +02001782static const unsigned int dell_m6_pin_configs[13] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001783 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02001784 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001785 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1786 0x4f0000f0,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001787};
1788
Takashi Iwai2b635362011-05-02 12:33:43 +02001789static const unsigned int alienware_m17x_pin_configs[13] = {
Takashi Iwai842ae632009-09-02 07:43:08 +02001790 0x0321101f, 0x0321101f, 0x03a11020, 0x03014020,
1791 0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0,
1792 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
1793 0x904601b0,
1794};
1795
Takashi Iwai2b635362011-05-02 12:33:43 +02001796static const unsigned int intel_dg45id_pin_configs[13] = {
Alexey Fisher52dc4382009-12-12 11:16:41 +02001797 0x02214230, 0x02A19240, 0x01013214, 0x01014210,
Wu Fengguang4d26f442010-05-07 08:47:54 +08001798 0x01A19250, 0x01011212, 0x01016211
Alexey Fisher52dc4382009-12-12 11:16:41 +02001799};
1800
Takashi Iwai2b635362011-05-02 12:33:43 +02001801static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01001802 [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001803 [STAC_DELL_M6_AMIC] = dell_m6_pin_configs,
1804 [STAC_DELL_M6_DMIC] = dell_m6_pin_configs,
1805 [STAC_DELL_M6_BOTH] = dell_m6_pin_configs,
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001806 [STAC_DELL_EQ] = dell_m6_pin_configs,
Takashi Iwai842ae632009-09-02 07:43:08 +02001807 [STAC_ALIENWARE_M17X] = alienware_m17x_pin_configs,
Alexey Fisher52dc4382009-12-12 11:16:41 +02001808 [STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001809};
1810
Takashi Iwaiea734962011-01-17 11:29:34 +01001811static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
Takashi Iwai1607b8e2009-02-26 16:50:43 +01001812 [STAC_92HD73XX_AUTO] = "auto",
Takashi Iwai9e43f0d2008-12-17 14:51:01 +01001813 [STAC_92HD73XX_NO_JD] = "no-jd",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001814 [STAC_92HD73XX_REF] = "ref",
Wu Fengguangae709442009-08-19 17:05:11 +08001815 [STAC_92HD73XX_INTEL] = "intel",
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001816 [STAC_DELL_M6_AMIC] = "dell-m6-amic",
1817 [STAC_DELL_M6_DMIC] = "dell-m6-dmic",
1818 [STAC_DELL_M6_BOTH] = "dell-m6",
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05001819 [STAC_DELL_EQ] = "dell-eq",
Takashi Iwai842ae632009-09-02 07:43:08 +02001820 [STAC_ALIENWARE_M17X] = "alienware",
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001821};
1822
Takashi Iwai2b635362011-05-02 12:33:43 +02001823static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001824 /* SigmaTel reference board */
1825 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Matthew Ranostaya7662642008-02-21 07:51:14 +01001826 "DFI LanParty", STAC_92HD73XX_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05001827 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
1828 "DFI LanParty", STAC_92HD73XX_REF),
Wu Fengguangae709442009-08-19 17:05:11 +08001829 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5002,
1830 "Intel DG45ID", STAC_92HD73XX_INTEL),
1831 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5003,
1832 "Intel DG45FC", STAC_92HD73XX_INTEL),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001833 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001834 "Dell Studio 1535", STAC_DELL_M6_DMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001835 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001836 "unknown Dell", STAC_DELL_M6_DMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001837 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001838 "unknown Dell", STAC_DELL_M6_BOTH),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001839 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001840 "unknown Dell", STAC_DELL_M6_BOTH),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001841 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001842 "unknown Dell", STAC_DELL_M6_AMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001843 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001844 "unknown Dell", STAC_DELL_M6_AMIC),
Matthew Ranostaya7662642008-02-21 07:51:14 +01001845 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001846 "unknown Dell", STAC_DELL_M6_DMIC),
1847 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272,
1848 "unknown Dell", STAC_DELL_M6_DMIC),
Takashi Iwaib0fc5e02008-11-21 08:37:03 +01001849 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
Takashi Iwai661cd8f2008-11-25 15:18:29 +01001850 "Dell Studio 1537", STAC_DELL_M6_DMIC),
Joerg Schirottkefa620e92008-12-19 08:13:49 +01001851 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
1852 "Dell Studio 17", STAC_DELL_M6_DMIC),
Takashi Iwai626f5ce2009-07-28 00:54:39 +02001853 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be,
1854 "Dell Studio 1555", STAC_DELL_M6_DMIC),
Daniel J Blueman8ef58372009-11-14 18:20:04 +00001855 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd,
1856 "Dell Studio 1557", STAC_DELL_M6_DMIC),
Daniel T Chenaac78da2010-04-21 20:41:52 -04001857 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
David Henningssonffe535e2012-01-16 10:52:20 +01001858 "Dell Studio XPS 1645", STAC_DELL_M6_DMIC),
Daniel T Chen5c1bccf2010-04-22 17:54:45 -04001859 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
David Henningssone033ebf2011-05-16 12:09:29 +02001860 "Dell Studio 1558", STAC_DELL_M6_DMIC),
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01001861 {} /* terminator */
1862};
1863
Takashi Iwai2b635362011-05-02 12:33:43 +02001864static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
Takashi Iwai842ae632009-09-02 07:43:08 +02001865 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
1866 "Alienware M17x", STAC_ALIENWARE_M17X),
Daniel T Chen0defe092010-12-01 19:16:07 -05001867 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
1868 "Alienware M17x", STAC_ALIENWARE_M17X),
Takashi Iwaidbd1b542011-11-19 11:41:30 +01001869 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
Albert Poolb9ecc4e2012-01-19 22:08:50 +01001870 "Alienware M17x R3", STAC_DELL_EQ),
Takashi Iwai842ae632009-09-02 07:43:08 +02001871 {} /* terminator */
1872};
1873
Takashi Iwai2b635362011-05-02 12:33:43 +02001874static const unsigned int ref92hd83xxx_pin_configs[10] = {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001875 0x02214030, 0x02211010, 0x02a19020, 0x02170130,
1876 0x01014050, 0x01819040, 0x01014020, 0x90a3014e,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001877 0x01451160, 0x98560170,
1878};
1879
Takashi Iwai2b635362011-05-02 12:33:43 +02001880static const unsigned int dell_s14_pin_configs[10] = {
Takashi Iwai69b56552009-09-15 12:37:42 +02001881 0x0221403f, 0x0221101f, 0x02a19020, 0x90170110,
1882 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160,
Matthew Ranostay8bb0ac52009-02-12 16:50:01 -05001883 0x40f000f0, 0x40f000f0,
1884};
1885
Julian Wollrathf7f9bdf2011-11-09 10:02:40 +01001886static const unsigned int dell_vostro_3500_pin_configs[10] = {
1887 0x02a11020, 0x0221101f, 0x400000f0, 0x90170110,
1888 0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160,
1889 0x400000f4, 0x400000f5,
1890};
1891
Takashi Iwai2b635362011-05-02 12:33:43 +02001892static const unsigned int hp_dv7_4000_pin_configs[10] = {
Steven Eastland48315592010-08-06 15:07:35 -06001893 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
1894 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
1895 0x40f000f0, 0x40f000f0,
1896};
1897
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06001898static const unsigned int hp_zephyr_pin_configs[10] = {
1899 0x01813050, 0x0421201f, 0x04a1205e, 0x96130310,
1900 0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130,
1901 0, 0,
1902};
1903
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -05001904static const unsigned int hp_cNB11_intquad_pin_configs[10] = {
1905 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110,
1906 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130,
1907 0x40f000f0, 0x40f000f0,
1908};
1909
Takashi Iwai2b635362011-05-02 12:33:43 +02001910static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001911 [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
Matthew Ranostay32ed3f42009-01-22 20:53:29 -05001912 [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
Matthew Ranostay8bb0ac52009-02-12 16:50:01 -05001913 [STAC_DELL_S14] = dell_s14_pin_configs,
Julian Wollrathf7f9bdf2011-11-09 10:02:40 +01001914 [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs,
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -05001915 [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
Steven Eastland48315592010-08-06 15:07:35 -06001916 [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06001917 [STAC_HP_ZEPHYR] = hp_zephyr_pin_configs,
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001918};
1919
Takashi Iwaiea734962011-01-17 11:29:34 +01001920static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
Takashi Iwai1607b8e2009-02-26 16:50:43 +01001921 [STAC_92HD83XXX_AUTO] = "auto",
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001922 [STAC_92HD83XXX_REF] = "ref",
Matthew Ranostay32ed3f42009-01-22 20:53:29 -05001923 [STAC_92HD83XXX_PWR_REF] = "mic-ref",
Matthew Ranostay8bb0ac52009-02-12 16:50:01 -05001924 [STAC_DELL_S14] = "dell-s14",
Julian Wollrathf7f9bdf2011-11-09 10:02:40 +01001925 [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -05001926 [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
Steven Eastland48315592010-08-06 15:07:35 -06001927 [STAC_HP_DV7_4000] = "hp-dv7-4000",
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06001928 [STAC_HP_ZEPHYR] = "hp-zephyr",
Takashi Iwaia3e19972012-07-26 08:17:20 +02001929 [STAC_92HD83XXX_HP_LED] = "hp-led",
Takashi Iwaiff8a1e22012-07-31 10:16:59 +02001930 [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led",
Takashi Iwai62cbde12012-09-14 11:58:54 +02001931 [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led",
David Henningsson8d032a82012-10-09 12:48:40 +02001932 [STAC_92HD83XXX_HEADSET_JACK] = "headset-jack",
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001933};
1934
Takashi Iwai2b635362011-05-02 12:33:43 +02001935static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02001936 /* SigmaTel reference board */
1937 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
Takashi Iwaif9d088b2009-01-13 11:54:49 +01001938 "DFI LanParty", STAC_92HD83XXX_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05001939 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
1940 "DFI LanParty", STAC_92HD83XXX_REF),
Matthew Ranostay8bb0ac52009-02-12 16:50:01 -05001941 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
1942 "unknown Dell", STAC_DELL_S14),
David Henningsson8d032a82012-10-09 12:48:40 +02001943 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0532,
1944 "Dell Latitude E6230", STAC_92HD83XXX_HEADSET_JACK),
1945 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0533,
1946 "Dell Latitude E6330", STAC_92HD83XXX_HEADSET_JACK),
1947 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0534,
1948 "Dell Latitude E6430", STAC_92HD83XXX_HEADSET_JACK),
1949 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0535,
1950 "Dell Latitude E6530", STAC_92HD83XXX_HEADSET_JACK),
1951 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053c,
1952 "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK),
1953 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053d,
1954 "Dell Latitude E5530", STAC_92HD83XXX_HEADSET_JACK),
1955 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0549,
1956 "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK),
1957 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x057d,
1958 "Dell Latitude E6430s", STAC_92HD83XXX_HEADSET_JACK),
1959 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0584,
1960 "Dell Latitude E6430U", STAC_92HD83XXX_HEADSET_JACK),
Julian Wollrathf7f9bdf2011-11-09 10:02:40 +01001961 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
1962 "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -05001963 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
1964 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1965 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
1966 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1967 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
1968 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1969 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
Takashi Iwai8ae58652012-12-13 14:33:42 +01001970 "HP Pavilion dv7", STAC_HP_DV7_4000),
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -05001971 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
1972 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1973 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
1974 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
Takashi Iwai62cbde12012-09-14 11:58:54 +02001975 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
1976 "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
Vitaliy Kulikov0c27c182011-07-22 17:50:37 -05001977 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
1978 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1979 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
1980 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1981 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
1982 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1983 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
1984 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1985 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
1986 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1987 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
1988 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1989 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
1990 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1991 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
1992 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1993 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
1994 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1995 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
1996 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1997 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
1998 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
1999 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
2000 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
2001 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
2002 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
2003 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
2004 "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06002005 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
2006 "HP", STAC_HP_ZEPHYR),
Takashi Iwaia3e19972012-07-26 08:17:20 +02002007 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660,
2008 "HP Mini", STAC_92HD83XXX_HP_LED),
Gustavo Maciel Dias Vieira5afc13a2012-10-26 12:51:53 -02002009 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E,
2010 "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED),
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06002011 {} /* terminator */
2012};
2013
2014static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = {
2015 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
2016 "HP", STAC_HP_ZEPHYR),
Herton Ronaldo Krzesinski574f3c42008-12-23 16:53:00 -02002017 {} /* terminator */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02002018};
2019
Takashi Iwai2b635362011-05-02 12:33:43 +02002020static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01002021 0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
Matthew Ranostay4b33c762008-10-10 09:07:23 -04002022 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -05002023 0x90a000f0, 0x01452050, 0x01452050, 0x00000000,
2024 0x00000000
Matthew Ranostaye035b842007-11-06 11:53:55 +01002025};
2026
Takashi Iwai2b635362011-05-02 12:33:43 +02002027static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01002028 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
Matthew Ranostay07bcb312008-03-20 12:10:57 +01002029 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -05002030 0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000,
2031 0x00000000
Matthew Ranostaya7662642008-02-21 07:51:14 +01002032};
2033
Takashi Iwai2b635362011-05-02 12:33:43 +02002034static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = {
Matthew Ranostaya7662642008-02-21 07:51:14 +01002035 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
2036 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -05002037 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
2038 0x00000000
Matthew Ranostaya7662642008-02-21 07:51:14 +01002039};
2040
Takashi Iwai2b635362011-05-02 12:33:43 +02002041static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = {
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05002042 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
2043 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0,
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -05002044 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000,
2045 0x00000000
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05002046};
2047
Takashi Iwai2b635362011-05-02 12:33:43 +02002048static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01002049 [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
Matthew Ranostaya7662642008-02-21 07:51:14 +01002050 [STAC_DELL_M4_1] = dell_m4_1_pin_configs,
2051 [STAC_DELL_M4_2] = dell_m4_2_pin_configs,
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05002052 [STAC_DELL_M4_3] = dell_m4_3_pin_configs,
Matthew Ranostay6a14f582008-09-12 12:02:30 -04002053 [STAC_HP_M4] = NULL,
Takashi Iwai2a6ce6e2010-05-12 10:16:20 +02002054 [STAC_HP_DV4] = NULL,
Takashi Iwai1b0652e2009-01-14 08:27:35 +01002055 [STAC_HP_DV5] = NULL,
Christoph Plattnerae6241f2009-03-08 23:19:05 +01002056 [STAC_HP_HDX] = NULL,
James Gardiner514bf542009-05-03 04:00:44 -04002057 [STAC_HP_DV4_1222NR] = NULL,
Matthew Ranostaye035b842007-11-06 11:53:55 +01002058};
2059
Takashi Iwaiea734962011-01-17 11:29:34 +01002060static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
Takashi Iwai1607b8e2009-02-26 16:50:43 +01002061 [STAC_92HD71BXX_AUTO] = "auto",
Matthew Ranostaye035b842007-11-06 11:53:55 +01002062 [STAC_92HD71BXX_REF] = "ref",
Matthew Ranostaya7662642008-02-21 07:51:14 +01002063 [STAC_DELL_M4_1] = "dell-m4-1",
2064 [STAC_DELL_M4_2] = "dell-m4-2",
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05002065 [STAC_DELL_M4_3] = "dell-m4-3",
Matthew Ranostay6a14f582008-09-12 12:02:30 -04002066 [STAC_HP_M4] = "hp-m4",
Takashi Iwai2a6ce6e2010-05-12 10:16:20 +02002067 [STAC_HP_DV4] = "hp-dv4",
Takashi Iwai1b0652e2009-01-14 08:27:35 +01002068 [STAC_HP_DV5] = "hp-dv5",
Christoph Plattnerae6241f2009-03-08 23:19:05 +01002069 [STAC_HP_HDX] = "hp-hdx",
James Gardiner514bf542009-05-03 04:00:44 -04002070 [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
Matthew Ranostaye035b842007-11-06 11:53:55 +01002071};
2072
Takashi Iwai2b635362011-05-02 12:33:43 +02002073static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
Matthew Ranostaye035b842007-11-06 11:53:55 +01002074 /* SigmaTel reference board */
2075 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2076 "DFI LanParty", STAC_92HD71BXX_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05002077 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
2078 "DFI LanParty", STAC_92HD71BXX_REF),
James Gardiner514bf542009-05-03 04:00:44 -04002079 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb,
2080 "HP dv4-1222nr", STAC_HP_DV4_1222NR),
Vitaliy Kulikov5bdaaad2009-11-04 07:57:45 +01002081 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720,
2082 "HP", STAC_HP_DV5),
Takashi Iwai58d83952009-03-13 17:04:34 +01002083 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
2084 "HP", STAC_HP_DV5),
Takashi Iwai2ae466f2009-02-16 14:16:36 +01002085 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
Takashi Iwai2a6ce6e2010-05-12 10:16:20 +02002086 "HP dv4-7", STAC_HP_DV4),
Takashi Iwai2ae466f2009-02-16 14:16:36 +01002087 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
2088 "HP dv4-7", STAC_HP_DV5),
Takashi Iwai6fce61a2009-03-10 07:48:57 +01002089 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
2090 "HP HDX", STAC_HP_HDX), /* HDX18 */
Matthew Ranostay9a9e2352008-09-26 10:37:03 -04002091 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
Takashi Iwai2ae466f2009-02-16 14:16:36 +01002092 "HP mini 1000", STAC_HP_M4),
Christoph Plattnerae6241f2009-03-08 23:19:05 +01002093 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
Takashi Iwai6fce61a2009-03-10 07:48:57 +01002094 "HP HDX", STAC_HP_HDX), /* HDX16 */
Takashi Iwai6e34c032009-09-14 15:42:18 +02002095 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620,
2096 "HP dv6", STAC_HP_DV5),
Kunal Gangakhedkare3d25302010-03-20 23:08:01 +05302097 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061,
2098 "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */
Luke Yelavich9b2167d2010-10-06 15:45:46 +11002099 SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x363e,
2100 "HP DV6", STAC_HP_DV5),
Takashi Iwai1972d022009-08-06 08:44:43 +02002101 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
2102 "HP", STAC_HP_DV5),
Matthew Ranostaya7662642008-02-21 07:51:14 +01002103 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
2104 "unknown Dell", STAC_DELL_M4_1),
2105 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
2106 "unknown Dell", STAC_DELL_M4_1),
2107 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
2108 "unknown Dell", STAC_DELL_M4_1),
2109 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
2110 "unknown Dell", STAC_DELL_M4_1),
2111 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
2112 "unknown Dell", STAC_DELL_M4_1),
2113 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
2114 "unknown Dell", STAC_DELL_M4_1),
2115 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
2116 "unknown Dell", STAC_DELL_M4_1),
2117 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
2118 "unknown Dell", STAC_DELL_M4_2),
2119 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
2120 "unknown Dell", STAC_DELL_M4_2),
2121 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
2122 "unknown Dell", STAC_DELL_M4_2),
2123 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
2124 "unknown Dell", STAC_DELL_M4_2),
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05002125 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa,
2126 "unknown Dell", STAC_DELL_M4_3),
Matthew Ranostaye035b842007-11-06 11:53:55 +01002127 {} /* terminator */
2128};
2129
Takashi Iwai0a427842013-01-14 15:20:13 +01002130static const struct hda_pintbl ref922x_pin_configs[] = {
2131 { 0x0a, 0x01014010 },
2132 { 0x0b, 0x01016011 },
2133 { 0x0c, 0x01012012 },
2134 { 0x0d, 0x0221401f },
2135 { 0x0e, 0x01813122 },
2136 { 0x0f, 0x01011014 },
2137 { 0x10, 0x01441030 },
2138 { 0x11, 0x01c41030 },
2139 { 0x15, 0x40000100 },
2140 { 0x1b, 0x40000100 },
2141 {}
Matt2f2f4252005-04-13 14:45:30 +02002142};
2143
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002144/*
2145 STAC 922X pin configs for
2146 102801A7
2147 102801AB
2148 102801A9
2149 102801D1
2150 102801D2
2151*/
Takashi Iwai0a427842013-01-14 15:20:13 +01002152static const struct hda_pintbl dell_922x_d81_pin_configs[] = {
2153 { 0x0a, 0x02214030 },
2154 { 0x0b, 0x01a19021 },
2155 { 0x0c, 0x01111012 },
2156 { 0x0d, 0x01114010 },
2157 { 0x0e, 0x02a19020 },
2158 { 0x0f, 0x01117011 },
2159 { 0x10, 0x400001f0 },
2160 { 0x11, 0x400001f1 },
2161 { 0x15, 0x01813122 },
2162 { 0x1b, 0x400001f2 },
2163 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002164};
2165
2166/*
2167 STAC 922X pin configs for
2168 102801AC
2169 102801D0
2170*/
Takashi Iwai0a427842013-01-14 15:20:13 +01002171static const struct hda_pintbl dell_922x_d82_pin_configs[] = {
2172 { 0x0a, 0x02214030 },
2173 { 0x0b, 0x01a19021 },
2174 { 0x0c, 0x01111012 },
2175 { 0x0d, 0x01114010 },
2176 { 0x0e, 0x02a19020 },
2177 { 0x0f, 0x01117011 },
2178 { 0x10, 0x01451140 },
2179 { 0x11, 0x400001f0 },
2180 { 0x15, 0x01813122 },
2181 { 0x1b, 0x400001f1 },
2182 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002183};
2184
2185/*
2186 STAC 922X pin configs for
2187 102801BF
2188*/
Takashi Iwai0a427842013-01-14 15:20:13 +01002189static const struct hda_pintbl dell_922x_m81_pin_configs[] = {
2190 { 0x0a, 0x0321101f },
2191 { 0x0b, 0x01112024 },
2192 { 0x0c, 0x01111222 },
2193 { 0x0d, 0x91174220 },
2194 { 0x0e, 0x03a11050 },
2195 { 0x0f, 0x01116221 },
2196 { 0x10, 0x90a70330 },
2197 { 0x11, 0x01452340 },
2198 { 0x15, 0x40C003f1 },
2199 { 0x1b, 0x405003f0 },
2200 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002201};
2202
2203/*
2204 STAC 9221 A1 pin configs for
2205 102801D7 (Dell XPS M1210)
2206*/
Takashi Iwai0a427842013-01-14 15:20:13 +01002207static const struct hda_pintbl dell_922x_m82_pin_configs[] = {
2208 { 0x0a, 0x02211211 },
2209 { 0x0b, 0x408103ff },
2210 { 0x0c, 0x02a1123e },
2211 { 0x0d, 0x90100310 },
2212 { 0x0e, 0x408003f1 },
2213 { 0x0f, 0x0221121f },
2214 { 0x10, 0x03451340 },
2215 { 0x11, 0x40c003f2 },
2216 { 0x15, 0x508003f3 },
2217 { 0x1b, 0x405003f4 },
2218 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002219};
2220
Takashi Iwai0a427842013-01-14 15:20:13 +01002221static const struct hda_pintbl d945gtp3_pin_configs[] = {
2222 { 0x0a, 0x0221401f },
2223 { 0x0b, 0x01a19022 },
2224 { 0x0c, 0x01813021 },
2225 { 0x0d, 0x01014010 },
2226 { 0x0e, 0x40000100 },
2227 { 0x0f, 0x40000100 },
2228 { 0x10, 0x40000100 },
2229 { 0x11, 0x40000100 },
2230 { 0x15, 0x02a19120 },
2231 { 0x1b, 0x40000100 },
2232 {}
Matt Porter403d1942005-11-29 15:00:51 +01002233};
2234
Takashi Iwai0a427842013-01-14 15:20:13 +01002235static const struct hda_pintbl d945gtp5_pin_configs[] = {
2236 { 0x0a, 0x0221401f },
2237 { 0x0b, 0x01011012 },
2238 { 0x0c, 0x01813024 },
2239 { 0x0d, 0x01014010 },
2240 { 0x0e, 0x01a19021 },
2241 { 0x0f, 0x01016011 },
2242 { 0x10, 0x01452130 },
2243 { 0x11, 0x40000100 },
2244 { 0x15, 0x02a19320 },
2245 { 0x1b, 0x40000100 },
2246 {}
Matt Porter403d1942005-11-29 15:00:51 +01002247};
2248
Takashi Iwai0a427842013-01-14 15:20:13 +01002249static const struct hda_pintbl intel_mac_v1_pin_configs[] = {
2250 { 0x0a, 0x0121e21f },
2251 { 0x0b, 0x400000ff },
2252 { 0x0c, 0x9017e110 },
2253 { 0x0d, 0x400000fd },
2254 { 0x0e, 0x400000fe },
2255 { 0x0f, 0x0181e020 },
2256 { 0x10, 0x1145e030 },
2257 { 0x11, 0x11c5e240 },
2258 { 0x15, 0x400000fc },
2259 { 0x1b, 0x400000fb },
2260 {}
Takashi Iwai3fc24d82007-02-16 13:27:18 +01002261};
2262
Takashi Iwai0a427842013-01-14 15:20:13 +01002263static const struct hda_pintbl intel_mac_v2_pin_configs[] = {
2264 { 0x0a, 0x0121e21f },
2265 { 0x0b, 0x90a7012e },
2266 { 0x0c, 0x9017e110 },
2267 { 0x0d, 0x400000fd },
2268 { 0x0e, 0x400000fe },
2269 { 0x0f, 0x0181e020 },
2270 { 0x10, 0x1145e230 },
2271 { 0x11, 0x500000fa },
2272 { 0x15, 0x400000fc },
2273 { 0x1b, 0x400000fb },
2274 {}
Sylvain FORETf16928f2007-04-27 14:22:36 +02002275};
2276
Takashi Iwai0a427842013-01-14 15:20:13 +01002277static const struct hda_pintbl intel_mac_v3_pin_configs[] = {
2278 { 0x0a, 0x0121e21f },
2279 { 0x0b, 0x90a7012e },
2280 { 0x0c, 0x9017e110 },
2281 { 0x0d, 0x400000fd },
2282 { 0x0e, 0x400000fe },
2283 { 0x0f, 0x0181e020 },
2284 { 0x10, 0x1145e230 },
2285 { 0x11, 0x11c5e240 },
2286 { 0x15, 0x400000fc },
2287 { 0x1b, 0x400000fb },
2288 {}
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002289};
2290
Takashi Iwai0a427842013-01-14 15:20:13 +01002291static const struct hda_pintbl intel_mac_v4_pin_configs[] = {
2292 { 0x0a, 0x0321e21f },
2293 { 0x0b, 0x03a1e02e },
2294 { 0x0c, 0x9017e110 },
2295 { 0x0d, 0x9017e11f },
2296 { 0x0e, 0x400000fe },
2297 { 0x0f, 0x0381e020 },
2298 { 0x10, 0x1345e230 },
2299 { 0x11, 0x13c5e240 },
2300 { 0x15, 0x400000fc },
2301 { 0x1b, 0x400000fb },
2302 {}
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02002303};
2304
Takashi Iwai0a427842013-01-14 15:20:13 +01002305static const struct hda_pintbl intel_mac_v5_pin_configs[] = {
2306 { 0x0a, 0x0321e21f },
2307 { 0x0b, 0x03a1e02e },
2308 { 0x0c, 0x9017e110 },
2309 { 0x0d, 0x9017e11f },
2310 { 0x0e, 0x400000fe },
2311 { 0x0f, 0x0381e020 },
2312 { 0x10, 0x1345e230 },
2313 { 0x11, 0x13c5e240 },
2314 { 0x15, 0x400000fc },
2315 { 0x1b, 0x400000fb },
2316 {}
Takashi Iwai0dae0f82007-05-21 12:41:29 +02002317};
2318
Takashi Iwai0a427842013-01-14 15:20:13 +01002319static const struct hda_pintbl ecs202_pin_configs[] = {
2320 { 0x0a, 0x0221401f },
2321 { 0x0b, 0x02a19020 },
2322 { 0x0c, 0x01a19020 },
2323 { 0x0d, 0x01114010 },
2324 { 0x0e, 0x408000f0 },
2325 { 0x0f, 0x01813022 },
2326 { 0x10, 0x074510a0 },
2327 { 0x11, 0x40c400f1 },
2328 { 0x15, 0x9037012e },
2329 { 0x1b, 0x40e000f2 },
2330 {}
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03002331};
Takashi Iwai76c08822007-06-19 12:17:42 +02002332
Takashi Iwai0a427842013-01-14 15:20:13 +01002333/* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */
2334static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = {
2335 SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1),
2336 SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2),
2337 SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2),
2338 SND_PCI_QUIRK(0x106b, 0x0e00, "Mac", STAC_INTEL_MAC_V3),
2339 SND_PCI_QUIRK(0x106b, 0x0f00, "Mac", STAC_INTEL_MAC_V3),
2340 SND_PCI_QUIRK(0x106b, 0x1600, "Mac", STAC_INTEL_MAC_V3),
2341 SND_PCI_QUIRK(0x106b, 0x1700, "Mac", STAC_INTEL_MAC_V3),
2342 SND_PCI_QUIRK(0x106b, 0x0200, "Mac", STAC_INTEL_MAC_V3),
2343 SND_PCI_QUIRK(0x106b, 0x1e00, "Mac", STAC_INTEL_MAC_V3),
2344 SND_PCI_QUIRK(0x106b, 0x1a00, "Mac", STAC_INTEL_MAC_V4),
2345 SND_PCI_QUIRK(0x106b, 0x0a00, "Mac", STAC_INTEL_MAC_V5),
2346 SND_PCI_QUIRK(0x106b, 0x2200, "Mac", STAC_INTEL_MAC_V5),
2347 {}
2348};
2349
2350static const struct hda_fixup stac922x_fixups[];
2351
2352/* remap the fixup from codec SSID and apply it */
2353static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec,
2354 const struct hda_fixup *fix,
2355 int action)
2356{
2357 if (action != HDA_FIXUP_ACT_PRE_PROBE)
2358 return;
2359 snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl,
2360 stac922x_fixups);
2361 if (codec->fixup_id != STAC_INTEL_MAC_AUTO)
2362 snd_hda_apply_fixup(codec, action);
2363}
2364
2365static void stac922x_fixup_intel_mac_gpio(struct hda_codec *codec,
2366 const struct hda_fixup *fix,
2367 int action)
2368{
2369 struct sigmatel_spec *spec = codec->spec;
2370
2371 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
2372 spec->gpio_mask = spec->gpio_dir = 0x03;
2373 spec->gpio_data = 0x03;
2374 }
2375}
2376
2377static const struct hda_fixup stac922x_fixups[] = {
2378 [STAC_D945_REF] = {
2379 .type = HDA_FIXUP_PINS,
2380 .v.pins = ref922x_pin_configs,
2381 },
2382 [STAC_D945GTP3] = {
2383 .type = HDA_FIXUP_PINS,
2384 .v.pins = d945gtp3_pin_configs,
2385 },
2386 [STAC_D945GTP5] = {
2387 .type = HDA_FIXUP_PINS,
2388 .v.pins = d945gtp5_pin_configs,
2389 },
2390 [STAC_INTEL_MAC_AUTO] = {
2391 .type = HDA_FIXUP_FUNC,
2392 .v.func = stac922x_fixup_intel_mac_auto,
2393 },
2394 [STAC_INTEL_MAC_V1] = {
2395 .type = HDA_FIXUP_PINS,
2396 .v.pins = intel_mac_v1_pin_configs,
2397 .chained = true,
2398 .chain_id = STAC_922X_INTEL_MAC_GPIO,
2399 },
2400 [STAC_INTEL_MAC_V2] = {
2401 .type = HDA_FIXUP_PINS,
2402 .v.pins = intel_mac_v2_pin_configs,
2403 .chained = true,
2404 .chain_id = STAC_922X_INTEL_MAC_GPIO,
2405 },
2406 [STAC_INTEL_MAC_V3] = {
2407 .type = HDA_FIXUP_PINS,
2408 .v.pins = intel_mac_v3_pin_configs,
2409 .chained = true,
2410 .chain_id = STAC_922X_INTEL_MAC_GPIO,
2411 },
2412 [STAC_INTEL_MAC_V4] = {
2413 .type = HDA_FIXUP_PINS,
2414 .v.pins = intel_mac_v4_pin_configs,
2415 .chained = true,
2416 .chain_id = STAC_922X_INTEL_MAC_GPIO,
2417 },
2418 [STAC_INTEL_MAC_V5] = {
2419 .type = HDA_FIXUP_PINS,
2420 .v.pins = intel_mac_v5_pin_configs,
2421 .chained = true,
2422 .chain_id = STAC_922X_INTEL_MAC_GPIO,
2423 },
2424 [STAC_922X_INTEL_MAC_GPIO] = {
2425 .type = HDA_FIXUP_FUNC,
2426 .v.func = stac922x_fixup_intel_mac_gpio,
2427 },
2428 [STAC_ECS_202] = {
2429 .type = HDA_FIXUP_PINS,
2430 .v.pins = ecs202_pin_configs,
2431 },
2432 [STAC_922X_DELL_D81] = {
2433 .type = HDA_FIXUP_PINS,
2434 .v.pins = dell_922x_d81_pin_configs,
2435 },
2436 [STAC_922X_DELL_D82] = {
2437 .type = HDA_FIXUP_PINS,
2438 .v.pins = dell_922x_d82_pin_configs,
2439 },
2440 [STAC_922X_DELL_M81] = {
2441 .type = HDA_FIXUP_PINS,
2442 .v.pins = dell_922x_m81_pin_configs,
2443 },
2444 [STAC_922X_DELL_M82] = {
2445 .type = HDA_FIXUP_PINS,
2446 .v.pins = dell_922x_m82_pin_configs,
2447 },
2448};
2449
2450static const struct hda_model_fixup stac922x_models[] = {
2451 { .id = STAC_D945_REF, .name = "ref" },
2452 { .id = STAC_D945GTP5, .name = "5stack" },
2453 { .id = STAC_D945GTP3, .name = "3stack" },
2454 { .id = STAC_INTEL_MAC_V1, .name = "intel-mac-v1" },
2455 { .id = STAC_INTEL_MAC_V2, .name = "intel-mac-v2" },
2456 { .id = STAC_INTEL_MAC_V3, .name = "intel-mac-v3" },
2457 { .id = STAC_INTEL_MAC_V4, .name = "intel-mac-v4" },
2458 { .id = STAC_INTEL_MAC_V5, .name = "intel-mac-v5" },
2459 { .id = STAC_INTEL_MAC_AUTO, .name = "intel-mac-auto" },
2460 { .id = STAC_ECS_202, .name = "ecs202" },
2461 { .id = STAC_922X_DELL_D81, .name = "dell-d81" },
2462 { .id = STAC_922X_DELL_D82, .name = "dell-d82" },
2463 { .id = STAC_922X_DELL_M81, .name = "dell-m81" },
2464 { .id = STAC_922X_DELL_M82, .name = "dell-m82" },
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002465 /* for backward compatibility */
Takashi Iwai0a427842013-01-14 15:20:13 +01002466 { .id = STAC_INTEL_MAC_V3, .name = "macmini" },
2467 { .id = STAC_INTEL_MAC_V5, .name = "macbook" },
2468 { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro-v1" },
2469 { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro" },
2470 { .id = STAC_INTEL_MAC_V2, .name = "imac-intel" },
2471 { .id = STAC_INTEL_MAC_V3, .name = "imac-intel-20" },
2472 {}
Matt Porter403d1942005-11-29 15:00:51 +01002473};
2474
Takashi Iwai0a427842013-01-14 15:20:13 +01002475static const struct snd_pci_quirk stac922x_fixup_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002476 /* SigmaTel reference board */
2477 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2478 "DFI LanParty", STAC_D945_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05002479 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
2480 "DFI LanParty", STAC_D945_REF),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002481 /* Intel 945G based systems */
2482 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
2483 "Intel D945G", STAC_D945GTP3),
2484 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
2485 "Intel D945G", STAC_D945GTP3),
2486 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
2487 "Intel D945G", STAC_D945GTP3),
2488 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
2489 "Intel D945G", STAC_D945GTP3),
2490 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
2491 "Intel D945G", STAC_D945GTP3),
2492 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
2493 "Intel D945G", STAC_D945GTP3),
2494 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
2495 "Intel D945G", STAC_D945GTP3),
2496 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
2497 "Intel D945G", STAC_D945GTP3),
2498 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
2499 "Intel D945G", STAC_D945GTP3),
2500 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
2501 "Intel D945G", STAC_D945GTP3),
2502 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
2503 "Intel D945G", STAC_D945GTP3),
2504 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
2505 "Intel D945G", STAC_D945GTP3),
2506 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
2507 "Intel D945G", STAC_D945GTP3),
2508 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
2509 "Intel D945G", STAC_D945GTP3),
2510 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
2511 "Intel D945G", STAC_D945GTP3),
2512 /* Intel D945G 5-stack systems */
2513 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
2514 "Intel D945G", STAC_D945GTP5),
2515 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
2516 "Intel D945G", STAC_D945GTP5),
2517 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
2518 "Intel D945G", STAC_D945GTP5),
2519 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
2520 "Intel D945G", STAC_D945GTP5),
2521 /* Intel 945P based systems */
2522 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
2523 "Intel D945P", STAC_D945GTP3),
2524 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
2525 "Intel D945P", STAC_D945GTP3),
2526 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
2527 "Intel D945P", STAC_D945GTP3),
2528 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
2529 "Intel D945P", STAC_D945GTP3),
2530 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
2531 "Intel D945P", STAC_D945GTP3),
2532 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
2533 "Intel D945P", STAC_D945GTP5),
Takashi Iwai8056d472009-01-23 09:09:43 +01002534 /* other intel */
2535 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
2536 "Intel D945", STAC_D945_REF),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002537 /* other systems */
Takashi Iwai0a427842013-01-14 15:20:13 +01002538
Nicolas Boichat536319a2008-07-21 22:18:01 +08002539 /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
Takashi Iwai0a427842013-01-14 15:20:13 +01002540 SND_PCI_QUIRK(0x8384, 0x7680, "Mac", STAC_INTEL_MAC_AUTO),
2541
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002542 /* Dell systems */
2543 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
2544 "unknown Dell", STAC_922X_DELL_D81),
2545 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
2546 "unknown Dell", STAC_922X_DELL_D81),
2547 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
2548 "unknown Dell", STAC_922X_DELL_D81),
2549 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
2550 "unknown Dell", STAC_922X_DELL_D82),
2551 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
2552 "unknown Dell", STAC_922X_DELL_M81),
2553 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
2554 "unknown Dell", STAC_922X_DELL_D82),
2555 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
2556 "unknown Dell", STAC_922X_DELL_D81),
2557 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
2558 "unknown Dell", STAC_922X_DELL_D81),
2559 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
2560 "Dell XPS M1210", STAC_922X_DELL_M82),
Mauro Carvalho Chehab8c650082008-08-04 10:39:59 -03002561 /* ECS/PC Chips boards */
Takashi Iwaidea0a502009-02-09 17:14:52 +01002562 SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000,
Herton Ronaldo Krzesinski8663ae52009-02-08 19:50:34 -02002563 "ECS/PC chips", STAC_ECS_202),
Matt Porter403d1942005-11-29 15:00:51 +01002564 {} /* terminator */
2565};
2566
Takashi Iwai2b635362011-05-02 12:33:43 +02002567static const unsigned int ref927x_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02002568 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2569 0x01a19040, 0x01011012, 0x01016011, 0x0101201f,
2570 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070,
2571 0x01c42190, 0x40000100,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002572};
2573
Takashi Iwai2b635362011-05-02 12:33:43 +02002574static const unsigned int d965_3st_pin_configs[14] = {
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002575 0x0221401f, 0x02a19120, 0x40000100, 0x01014011,
2576 0x01a19021, 0x01813024, 0x40000100, 0x40000100,
2577 0x40000100, 0x40000100, 0x40000100, 0x40000100,
2578 0x40000100, 0x40000100
2579};
2580
Takashi Iwai2b635362011-05-02 12:33:43 +02002581static const unsigned int d965_5st_pin_configs[14] = {
Tobin Davis93ed1502006-09-01 21:03:12 +02002582 0x02214020, 0x02a19080, 0x0181304e, 0x01014010,
2583 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
2584 0x40000100, 0x40000100, 0x40000100, 0x01442070,
2585 0x40000100, 0x40000100
2586};
2587
Takashi Iwai2b635362011-05-02 12:33:43 +02002588static const unsigned int d965_5st_no_fp_pin_configs[14] = {
Takashi Iwai679d92e2009-05-24 19:00:08 +02002589 0x40000100, 0x40000100, 0x0181304e, 0x01014010,
2590 0x01a19040, 0x01011012, 0x01016011, 0x40000100,
2591 0x40000100, 0x40000100, 0x40000100, 0x01442070,
2592 0x40000100, 0x40000100
2593};
2594
Takashi Iwai2b635362011-05-02 12:33:43 +02002595static const unsigned int dell_3st_pin_configs[14] = {
Tobin Davis4ff076e2007-08-07 11:48:12 +02002596 0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
2597 0x01111212, 0x01116211, 0x01813050, 0x01112214,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002598 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
Tobin Davis4ff076e2007-08-07 11:48:12 +02002599 0x40c003fc, 0x40000100
2600};
2601
Takashi Iwai2b635362011-05-02 12:33:43 +02002602static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
Takashi Iwaie28d8322008-12-17 13:48:29 +01002603 [STAC_D965_REF_NO_JD] = ref927x_pin_configs,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002604 [STAC_D965_REF] = ref927x_pin_configs,
2605 [STAC_D965_3ST] = d965_3st_pin_configs,
2606 [STAC_D965_5ST] = d965_5st_pin_configs,
Takashi Iwai679d92e2009-05-24 19:00:08 +02002607 [STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs,
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002608 [STAC_DELL_3ST] = dell_3st_pin_configs,
2609 [STAC_DELL_BIOS] = NULL,
Takashi Iwai54930532009-10-11 17:38:29 +02002610 [STAC_927X_VOLKNOB] = NULL,
Matt Porter3cc08dc2006-01-23 15:27:49 +01002611};
2612
Takashi Iwaiea734962011-01-17 11:29:34 +01002613static const char * const stac927x_models[STAC_927X_MODELS] = {
Takashi Iwai1607b8e2009-02-26 16:50:43 +01002614 [STAC_927X_AUTO] = "auto",
Takashi Iwaie28d8322008-12-17 13:48:29 +01002615 [STAC_D965_REF_NO_JD] = "ref-no-jd",
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002616 [STAC_D965_REF] = "ref",
2617 [STAC_D965_3ST] = "3stack",
2618 [STAC_D965_5ST] = "5stack",
Takashi Iwai679d92e2009-05-24 19:00:08 +02002619 [STAC_D965_5ST_NO_FP] = "5stack-no-fp",
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002620 [STAC_DELL_3ST] = "dell-3stack",
2621 [STAC_DELL_BIOS] = "dell-bios",
Takashi Iwai54930532009-10-11 17:38:29 +02002622 [STAC_927X_VOLKNOB] = "volknob",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002623};
2624
Takashi Iwai2b635362011-05-02 12:33:43 +02002625static const struct snd_pci_quirk stac927x_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002626 /* SigmaTel reference board */
2627 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2628 "DFI LanParty", STAC_D965_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05002629 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
2630 "DFI LanParty", STAC_D965_REF),
Tobin Davis81d3dbd2006-08-22 19:44:45 +02002631 /* Intel 946 based systems */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002632 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
2633 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
Tobin Davis93ed1502006-09-01 21:03:12 +02002634 /* 965 based 3 stack systems */
Takashi Iwaidea0a502009-02-09 17:14:52 +01002635 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100,
2636 "Intel D965", STAC_D965_3ST),
2637 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
2638 "Intel D965", STAC_D965_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002639 /* Dell 3 stack systems */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002640 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
Tobin Davis4ff076e2007-08-07 11:48:12 +02002641 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST),
2642 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002643 /* Dell 3 stack systems with verb table in BIOS */
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002644 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
Daniel T Chen66668b62010-05-23 20:47:45 -04002645 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_BIOS),
Matthew Ranostay2f32d902008-01-10 13:06:26 +01002646 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002647 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS),
Chengu Wang84d3dc22009-07-30 19:43:55 +08002648 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01002649 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS),
2650 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS),
2651 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS),
2652 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
Tobin Davis93ed1502006-09-01 21:03:12 +02002653 /* 965 based 5 stack systems */
Takashi Iwaidea0a502009-02-09 17:14:52 +01002654 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300,
2655 "Intel D965", STAC_D965_5ST),
2656 SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
2657 "Intel D965", STAC_D965_5ST),
Takashi Iwai54930532009-10-11 17:38:29 +02002658 /* volume-knob fixes */
2659 SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
Matt Porter3cc08dc2006-01-23 15:27:49 +01002660 {} /* terminator */
2661};
2662
Takashi Iwaife6322c2013-01-14 14:46:51 +01002663static const struct hda_pintbl ref9205_pin_configs[] = {
2664 { 0x0a, 0x40000100 },
2665 { 0x0b, 0x40000100 },
2666 { 0x0c, 0x01016011 },
2667 { 0x0d, 0x01014010 },
2668 { 0x0e, 0x01813122 },
2669 { 0x0f, 0x01a19021 },
2670 { 0x14, 0x01019020 },
2671 { 0x16, 0x40000100 },
2672 { 0x17, 0x90a000f0 },
2673 { 0x18, 0x90a000f0 },
2674 { 0x21, 0x01441030 },
2675 { 0x22, 0x01c41030 },
2676 {}
Matt Porterf3302a52006-07-31 12:49:34 +02002677};
2678
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002679/*
2680 STAC 9205 pin configs for
2681 102801F1
2682 102801F2
2683 102801FC
2684 102801FD
2685 10280204
2686 1028021F
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002687 10280228 (Dell Vostro 1500)
Anisse Astier95e70e82009-12-23 17:28:45 +01002688 10280229 (Dell Vostro 1700)
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002689*/
Takashi Iwaife6322c2013-01-14 14:46:51 +01002690static const struct hda_pintbl dell_9205_m42_pin_configs[] = {
2691 { 0x0a, 0x0321101F },
2692 { 0x0b, 0x03A11020 },
2693 { 0x0c, 0x400003FA },
2694 { 0x0d, 0x90170310 },
2695 { 0x0e, 0x400003FB },
2696 { 0x0f, 0x400003FC },
2697 { 0x14, 0x400003FD },
2698 { 0x16, 0x40F000F9 },
2699 { 0x17, 0x90A60330 },
2700 { 0x18, 0x400003FF },
2701 { 0x21, 0x0144131F },
2702 { 0x22, 0x40C003FE },
2703 {}
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002704};
2705
2706/*
2707 STAC 9205 pin configs for
2708 102801F9
2709 102801FA
2710 102801FE
2711 102801FF (Dell Precision M4300)
2712 10280206
2713 10280200
2714 10280201
2715*/
Takashi Iwaife6322c2013-01-14 14:46:51 +01002716static const struct hda_pintbl dell_9205_m43_pin_configs[] = {
2717 { 0x0a, 0x0321101f },
2718 { 0x0b, 0x03a11020 },
2719 { 0x0c, 0x90a70330 },
2720 { 0x0d, 0x90170310 },
2721 { 0x0e, 0x400000fe },
2722 { 0x0f, 0x400000ff },
2723 { 0x14, 0x400000fd },
2724 { 0x16, 0x40f000f9 },
2725 { 0x17, 0x400000fa },
2726 { 0x18, 0x400000fc },
2727 { 0x21, 0x0144131f },
2728 { 0x22, 0x40c003f8 },
2729 /* Enable SPDIF in/out */
2730 { 0x1f, 0x01441030 },
2731 { 0x20, 0x1c410030 },
2732 {}
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002733};
2734
Takashi Iwaife6322c2013-01-14 14:46:51 +01002735static const struct hda_pintbl dell_9205_m44_pin_configs[] = {
2736 { 0x0a, 0x0421101f },
2737 { 0x0b, 0x04a11020 },
2738 { 0x0c, 0x400003fa },
2739 { 0x0d, 0x90170310 },
2740 { 0x0e, 0x400003fb },
2741 { 0x0f, 0x400003fc },
2742 { 0x14, 0x400003fd },
2743 { 0x16, 0x400003f9 },
2744 { 0x17, 0x90a60330 },
2745 { 0x18, 0x400003ff },
2746 { 0x21, 0x01441340 },
2747 { 0x22, 0x40c003fe },
2748 {}
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002749};
2750
Takashi Iwaife6322c2013-01-14 14:46:51 +01002751static void stac9205_fixup_ref(struct hda_codec *codec,
2752 const struct hda_fixup *fix, int action)
2753{
2754 struct sigmatel_spec *spec = codec->spec;
2755
2756 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
2757 snd_hda_apply_pincfgs(codec, ref9205_pin_configs);
2758 /* SPDIF-In enabled */
2759 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0;
2760 }
2761}
2762
2763static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
2764 unsigned char type, int data);
2765
2766static void stac9205_fixup_dell_m43(struct hda_codec *codec,
2767 const struct hda_fixup *fix, int action)
2768{
2769 struct sigmatel_spec *spec = codec->spec;
2770 int err;
2771
2772 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
2773 snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
2774
2775 /* Enable unsol response for GPIO4/Dock HP connection */
2776 err = stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x01);
2777 if (err < 0)
2778 return;
2779 snd_hda_codec_write_cache(codec, codec->afg, 0,
2780 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
2781 snd_hda_jack_detect_enable(codec, codec->afg, 0);
2782
2783 spec->gpio_dir = 0x0b;
2784 spec->eapd_mask = 0x01;
2785 spec->gpio_mask = 0x1b;
2786 spec->gpio_mute = 0x10;
2787 /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
2788 * GPIO3 Low = DRM
2789 */
2790 spec->gpio_data = 0x01;
2791 }
2792}
2793
2794static void stac9205_fixup_eapd(struct hda_codec *codec,
2795 const struct hda_fixup *fix, int action)
2796{
2797 struct sigmatel_spec *spec = codec->spec;
2798
2799 if (action == HDA_FIXUP_ACT_PRE_PROBE)
2800 spec->eapd_switch = 0;
2801}
2802
2803static const struct hda_fixup stac9205_fixups[] = {
2804 [STAC_9205_REF] = {
2805 .type = HDA_FIXUP_FUNC,
2806 .v.func = stac9205_fixup_ref,
2807 },
2808 [STAC_9205_DELL_M42] = {
2809 .type = HDA_FIXUP_PINS,
2810 .v.pins = dell_9205_m42_pin_configs,
2811 },
2812 [STAC_9205_DELL_M43] = {
2813 .type = HDA_FIXUP_FUNC,
2814 .v.func = stac9205_fixup_dell_m43,
2815 },
2816 [STAC_9205_DELL_M44] = {
2817 .type = HDA_FIXUP_PINS,
2818 .v.pins = dell_9205_m44_pin_configs,
2819 },
2820 [STAC_9205_EAPD] = {
2821 .type = HDA_FIXUP_FUNC,
2822 .v.func = stac9205_fixup_eapd,
2823 },
2824 {}
Matt Porterf3302a52006-07-31 12:49:34 +02002825};
2826
Takashi Iwaife6322c2013-01-14 14:46:51 +01002827static const struct hda_model_fixup stac9205_models[] = {
2828 { .id = STAC_9205_REF, .name = "ref" },
2829 { .id = STAC_9205_DELL_M42, .name = "dell-m42" },
2830 { .id = STAC_9205_DELL_M43, .name = "dell-m43" },
2831 { .id = STAC_9205_DELL_M44, .name = "dell-m44" },
2832 { .id = STAC_9205_EAPD, .name = "eapd" },
2833 {}
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002834};
2835
Takashi Iwaife6322c2013-01-14 14:46:51 +01002836static const struct snd_pci_quirk stac9205_fixup_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002837 /* SigmaTel reference board */
2838 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
2839 "DFI LanParty", STAC_9205_REF),
Herton Ronaldo Krzesinski02358fc2009-07-04 01:44:59 -03002840 SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
2841 "SigmaTel", STAC_9205_REF),
Matthew Ranostay577aa2c2009-01-22 22:55:44 -05002842 SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
2843 "DFI LanParty", STAC_9205_REF),
Takashi Iwaid9a42682009-01-22 17:40:18 +01002844 /* Dell */
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002845 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
2846 "unknown Dell", STAC_9205_DELL_M42),
2847 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
2848 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002849 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
Matthew Ranostayb44ef2f2007-09-18 00:52:38 +02002850 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002851 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
2852 "Dell Precision", STAC_9205_DELL_M43),
2853 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
2854 "Dell Precision", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002855 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
2856 "unknown Dell", STAC_9205_DELL_M42),
2857 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
2858 "unknown Dell", STAC_9205_DELL_M42),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002859 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
2860 "Dell Precision", STAC_9205_DELL_M43),
2861 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002862 "Dell Precision M4300", STAC_9205_DELL_M43),
Takashi Iwaidfe495d2007-08-23 19:04:28 +02002863 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
2864 "unknown Dell", STAC_9205_DELL_M42),
Takashi Iwai45499152008-06-12 16:27:24 +02002865 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
2866 "Dell Precision", STAC_9205_DELL_M43),
2867 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
2868 "Dell Precision", STAC_9205_DELL_M43),
2869 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
2870 "Dell Precision", STAC_9205_DELL_M43),
Tobin Davisae0a8ed2007-08-13 15:50:29 +02002871 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
2872 "Dell Inspiron", STAC_9205_DELL_M44),
Matthew Ranostay3fa2ef72008-01-11 11:39:06 +01002873 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
2874 "Dell Vostro 1500", STAC_9205_DELL_M42),
Anisse Astier95e70e82009-12-23 17:28:45 +01002875 SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0229,
2876 "Dell Vostro 1700", STAC_9205_DELL_M42),
Takashi Iwaid9a42682009-01-22 17:40:18 +01002877 /* Gateway */
Hao Song42b95f02009-07-20 15:01:16 +08002878 SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
Takashi Iwaid9a42682009-01-22 17:40:18 +01002879 SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
Matt Porterf3302a52006-07-31 12:49:34 +02002880 {} /* terminator */
2881};
2882
Takashi Iwai330ee992009-02-20 14:33:36 +01002883static void stac92xx_set_config_regs(struct hda_codec *codec,
Takashi Iwai2b635362011-05-02 12:33:43 +02002884 const unsigned int *pincfgs)
Matt2f2f4252005-04-13 14:45:30 +02002885{
2886 int i;
2887 struct sigmatel_spec *spec = codec->spec;
Matt2f2f4252005-04-13 14:45:30 +02002888
Takashi Iwai330ee992009-02-20 14:33:36 +01002889 if (!pincfgs)
2890 return;
Richard Fish11b44bb2006-08-23 18:31:34 +02002891
Matthew Ranostay87d48362007-07-17 11:52:24 +02002892 for (i = 0; i < spec->num_pins; i++)
Takashi Iwai330ee992009-02-20 14:33:36 +01002893 if (spec->pin_nids[i] && pincfgs[i])
2894 snd_hda_codec_set_pincfg(codec, spec->pin_nids[i],
2895 pincfgs[i]);
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01002896}
2897
Matt2f2f4252005-04-13 14:45:30 +02002898/*
2899 * Analog playback callbacks
2900 */
2901static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
2902 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002903 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002904{
2905 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002906 if (spec->stream_delay)
2907 msleep(spec->stream_delay);
Takashi Iwai9a081602008-02-12 18:37:26 +01002908 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2909 hinfo);
Matt2f2f4252005-04-13 14:45:30 +02002910}
2911
2912static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2913 struct hda_codec *codec,
2914 unsigned int stream_tag,
2915 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002916 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002917{
2918 struct sigmatel_spec *spec = codec->spec;
Matt Porter403d1942005-11-29 15:00:51 +01002919 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream);
Matt2f2f4252005-04-13 14:45:30 +02002920}
2921
2922static int stac92xx_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2923 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002924 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002925{
2926 struct sigmatel_spec *spec = codec->spec;
2927 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2928}
2929
2930/*
Mattdabbed62005-06-14 10:19:34 +02002931 * Digital playback callbacks
2932 */
2933static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2934 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002935 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002936{
2937 struct sigmatel_spec *spec = codec->spec;
2938 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2939}
2940
2941static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2942 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002943 struct snd_pcm_substream *substream)
Mattdabbed62005-06-14 10:19:34 +02002944{
2945 struct sigmatel_spec *spec = codec->spec;
2946 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2947}
2948
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002949static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2950 struct hda_codec *codec,
2951 unsigned int stream_tag,
2952 unsigned int format,
2953 struct snd_pcm_substream *substream)
2954{
2955 struct sigmatel_spec *spec = codec->spec;
2956 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2957 stream_tag, format, substream);
2958}
2959
Takashi Iwai9411e212009-02-13 11:32:28 +01002960static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2961 struct hda_codec *codec,
2962 struct snd_pcm_substream *substream)
2963{
2964 struct sigmatel_spec *spec = codec->spec;
2965 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
2966}
2967
Mattdabbed62005-06-14 10:19:34 +02002968
2969/*
Matt2f2f4252005-04-13 14:45:30 +02002970 * Analog capture callbacks
2971 */
2972static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2973 struct hda_codec *codec,
2974 unsigned int stream_tag,
2975 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002976 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002977{
2978 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002979 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002980
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002981 if (spec->powerdown_adcs) {
2982 msleep(40);
Takashi Iwai8c2f7672008-12-01 11:54:35 +01002983 snd_hda_codec_write(codec, nid, 0,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002984 AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
2985 }
2986 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Matt2f2f4252005-04-13 14:45:30 +02002987 return 0;
2988}
2989
2990static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2991 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002992 struct snd_pcm_substream *substream)
Matt2f2f4252005-04-13 14:45:30 +02002993{
2994 struct sigmatel_spec *spec = codec->spec;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002995 hda_nid_t nid = spec->adc_nids[substream->number];
Matt2f2f4252005-04-13 14:45:30 +02002996
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02002997 snd_hda_codec_cleanup_stream(codec, nid);
2998 if (spec->powerdown_adcs)
Takashi Iwai8c2f7672008-12-01 11:54:35 +01002999 snd_hda_codec_write(codec, nid, 0,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02003000 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Matt2f2f4252005-04-13 14:45:30 +02003001 return 0;
3002}
3003
Takashi Iwai2b635362011-05-02 12:33:43 +02003004static const struct hda_pcm_stream stac92xx_pcm_digital_playback = {
Mattdabbed62005-06-14 10:19:34 +02003005 .substreams = 1,
3006 .channels_min = 2,
3007 .channels_max = 2,
3008 /* NID is set in stac92xx_build_pcms */
3009 .ops = {
3010 .open = stac92xx_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003011 .close = stac92xx_dig_playback_pcm_close,
Takashi Iwai9411e212009-02-13 11:32:28 +01003012 .prepare = stac92xx_dig_playback_pcm_prepare,
3013 .cleanup = stac92xx_dig_playback_pcm_cleanup
Mattdabbed62005-06-14 10:19:34 +02003014 },
3015};
3016
Takashi Iwai2b635362011-05-02 12:33:43 +02003017static const struct hda_pcm_stream stac92xx_pcm_digital_capture = {
Mattdabbed62005-06-14 10:19:34 +02003018 .substreams = 1,
3019 .channels_min = 2,
3020 .channels_max = 2,
3021 /* NID is set in stac92xx_build_pcms */
3022};
3023
Takashi Iwai2b635362011-05-02 12:33:43 +02003024static const struct hda_pcm_stream stac92xx_pcm_analog_playback = {
Matt2f2f4252005-04-13 14:45:30 +02003025 .substreams = 1,
3026 .channels_min = 2,
Mattc7d4b2f2005-06-27 14:59:41 +02003027 .channels_max = 8,
Matt2f2f4252005-04-13 14:45:30 +02003028 .nid = 0x02, /* NID to query formats and rates */
3029 .ops = {
3030 .open = stac92xx_playback_pcm_open,
3031 .prepare = stac92xx_playback_pcm_prepare,
3032 .cleanup = stac92xx_playback_pcm_cleanup
3033 },
3034};
3035
Takashi Iwai2b635362011-05-02 12:33:43 +02003036static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
Matt Porter3cc08dc2006-01-23 15:27:49 +01003037 .substreams = 1,
3038 .channels_min = 2,
3039 .channels_max = 2,
3040 .nid = 0x06, /* NID to query formats and rates */
3041 .ops = {
3042 .open = stac92xx_playback_pcm_open,
3043 .prepare = stac92xx_playback_pcm_prepare,
3044 .cleanup = stac92xx_playback_pcm_cleanup
3045 },
3046};
3047
Takashi Iwai2b635362011-05-02 12:33:43 +02003048static const struct hda_pcm_stream stac92xx_pcm_analog_capture = {
Matt2f2f4252005-04-13 14:45:30 +02003049 .channels_min = 2,
3050 .channels_max = 2,
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003051 /* NID + .substreams is set in stac92xx_build_pcms */
Matt2f2f4252005-04-13 14:45:30 +02003052 .ops = {
3053 .prepare = stac92xx_capture_pcm_prepare,
3054 .cleanup = stac92xx_capture_pcm_cleanup
3055 },
3056};
3057
3058static int stac92xx_build_pcms(struct hda_codec *codec)
3059{
3060 struct sigmatel_spec *spec = codec->spec;
3061 struct hda_pcm *info = spec->pcm_rec;
3062
3063 codec->num_pcms = 1;
3064 codec->pcm_info = info;
3065
Mattc7d4b2f2005-06-27 14:59:41 +02003066 info->name = "STAC92xx Analog";
Matt2f2f4252005-04-13 14:45:30 +02003067 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
Takashi Iwai00a602d2009-01-23 11:55:42 +01003068 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3069 spec->multiout.dac_nids[0];
Takashi Iwaiee81abb2012-11-08 17:12:10 +01003070 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
3071 spec->autocfg.line_outs == 2)
3072 info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
3073 snd_pcm_2_1_chmaps;
3074
Matt2f2f4252005-04-13 14:45:30 +02003075 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
Matt Porter3cc08dc2006-01-23 15:27:49 +01003076 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02003077 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
Matt Porter3cc08dc2006-01-23 15:27:49 +01003078
3079 if (spec->alt_switch) {
3080 codec->num_pcms++;
3081 info++;
3082 info->name = "STAC92xx Analog Alt";
3083 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback;
3084 }
Matt2f2f4252005-04-13 14:45:30 +02003085
Mattdabbed62005-06-14 10:19:34 +02003086 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
3087 codec->num_pcms++;
3088 info++;
3089 info->name = "STAC92xx Digital";
Takashi Iwai0852d7a2009-02-11 11:35:15 +01003090 info->pcm_type = spec->autocfg.dig_out_type[0];
Mattdabbed62005-06-14 10:19:34 +02003091 if (spec->multiout.dig_out_nid) {
3092 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
3093 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3094 }
3095 if (spec->dig_in_nid) {
3096 info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture;
3097 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3098 }
3099 }
3100
Matt2f2f4252005-04-13 14:45:30 +02003101 return 0;
3102}
3103
Matt Porter403d1942005-11-29 15:00:51 +01003104static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
3105
3106{
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02003107 snd_hda_set_pin_ctl_cache(codec, nid, pin_type);
Matt Porter403d1942005-11-29 15:00:51 +01003108}
3109
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003110#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
3111
3112static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
3113 struct snd_ctl_elem_value *ucontrol)
3114{
3115 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3116 struct sigmatel_spec *spec = codec->spec;
3117
Takashi Iwaid7a89432008-11-12 09:48:04 +01003118 ucontrol->value.integer.value[0] = !!spec->hp_switch;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003119 return 0;
3120}
3121
Takashi Iwai62558ce2009-07-29 14:23:09 +02003122static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid);
Takashi Iwaic6e4c662008-11-25 11:58:19 +01003123
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003124static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
3125 struct snd_ctl_elem_value *ucontrol)
3126{
3127 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3128 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaid7a89432008-11-12 09:48:04 +01003129 int nid = kcontrol->private_value;
3130
3131 spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003132
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003133 /* check to be sure that the ports are up to date with
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003134 * switch changes
3135 */
Takashi Iwai62558ce2009-07-29 14:23:09 +02003136 stac_issue_unsol_event(codec, nid);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003137
3138 return 1;
3139}
3140
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003141static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol,
3142 struct snd_ctl_elem_info *uinfo)
3143{
3144 int i;
Takashi Iwai2b635362011-05-02 12:33:43 +02003145 static const char * const texts[] = {
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003146 "Mic In", "Line In", "Line Out"
3147 };
3148
3149 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3150 struct sigmatel_spec *spec = codec->spec;
3151 hda_nid_t nid = kcontrol->private_value;
3152
3153 if (nid == spec->mic_switch || nid == spec->line_switch)
3154 i = 3;
3155 else
3156 i = 2;
3157
3158 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3159 uinfo->value.enumerated.items = i;
3160 uinfo->count = 1;
3161 if (uinfo->value.enumerated.item >= i)
3162 uinfo->value.enumerated.item = i-1;
3163 strcpy(uinfo->value.enumerated.name,
3164 texts[uinfo->value.enumerated.item]);
3165
3166 return 0;
3167}
3168
3169static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
3170 struct snd_ctl_elem_value *ucontrol)
3171{
3172 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3173 hda_nid_t nid = kcontrol->private_value;
3174 unsigned int vref = stac92xx_vref_get(codec, nid);
3175
Takashi Iwai47408602012-04-20 13:06:53 +02003176 if (vref == snd_hda_get_default_vref(codec, nid))
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003177 ucontrol->value.enumerated.item[0] = 0;
3178 else if (vref == AC_PINCTL_VREF_GRD)
3179 ucontrol->value.enumerated.item[0] = 1;
3180 else if (vref == AC_PINCTL_VREF_HIZ)
3181 ucontrol->value.enumerated.item[0] = 2;
3182
3183 return 0;
3184}
3185
3186static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
3187 struct snd_ctl_elem_value *ucontrol)
3188{
3189 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3190 unsigned int new_vref = 0;
Takashi Iwaib8621512009-06-22 08:00:10 +02003191 int error;
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003192 hda_nid_t nid = kcontrol->private_value;
3193
3194 if (ucontrol->value.enumerated.item[0] == 0)
Takashi Iwai47408602012-04-20 13:06:53 +02003195 new_vref = snd_hda_get_default_vref(codec, nid);
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003196 else if (ucontrol->value.enumerated.item[0] == 1)
3197 new_vref = AC_PINCTL_VREF_GRD;
3198 else if (ucontrol->value.enumerated.item[0] == 2)
3199 new_vref = AC_PINCTL_VREF_HIZ;
3200 else
3201 return 0;
3202
3203 if (new_vref != stac92xx_vref_get(codec, nid)) {
3204 error = stac92xx_vref_set(codec, nid, new_vref);
3205 return error;
3206 }
3207
3208 return 0;
3209}
3210
3211static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol,
3212 struct snd_ctl_elem_info *uinfo)
3213{
Takashi Iwai2b635362011-05-02 12:33:43 +02003214 char *texts[2];
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003215 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3216 struct sigmatel_spec *spec = codec->spec;
3217
3218 if (kcontrol->private_value == spec->line_switch)
3219 texts[0] = "Line In";
3220 else
3221 texts[0] = "Mic In";
3222 texts[1] = "Line Out";
3223 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3224 uinfo->value.enumerated.items = 2;
3225 uinfo->count = 1;
3226
3227 if (uinfo->value.enumerated.item >= 2)
3228 uinfo->value.enumerated.item = 1;
3229 strcpy(uinfo->value.enumerated.name,
3230 texts[uinfo->value.enumerated.item]);
3231
3232 return 0;
3233}
Matt Porter403d1942005-11-29 15:00:51 +01003234
3235static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3236{
3237 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3238 struct sigmatel_spec *spec = codec->spec;
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003239 hda_nid_t nid = kcontrol->private_value;
3240 int io_idx = (nid == spec->mic_switch) ? 1 : 0;
Matt Porter403d1942005-11-29 15:00:51 +01003241
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003242 ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx];
Matt Porter403d1942005-11-29 15:00:51 +01003243 return 0;
3244}
3245
3246static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3247{
3248 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3249 struct sigmatel_spec *spec = codec->spec;
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003250 hda_nid_t nid = kcontrol->private_value;
3251 int io_idx = (nid == spec->mic_switch) ? 1 : 0;
3252 unsigned short val = !!ucontrol->value.enumerated.item[0];
Matt Porter403d1942005-11-29 15:00:51 +01003253
3254 spec->io_switch[io_idx] = val;
3255
3256 if (val)
3257 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
Takashi Iwaic960a032006-03-23 17:06:28 +01003258 else {
3259 unsigned int pinctl = AC_PINCTL_IN_EN;
3260 if (io_idx) /* set VREF for mic */
Takashi Iwai47408602012-04-20 13:06:53 +02003261 pinctl |= snd_hda_get_default_vref(codec, nid);
Takashi Iwaic960a032006-03-23 17:06:28 +01003262 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3263 }
Jiang Zhe40c1d302007-11-12 13:05:16 +01003264
3265 /* check the auto-mute again: we need to mute/unmute the speaker
3266 * appropriately according to the pin direction
3267 */
3268 if (spec->hp_detect)
Takashi Iwai62558ce2009-07-29 14:23:09 +02003269 stac_issue_unsol_event(codec, nid);
Jiang Zhe40c1d302007-11-12 13:05:16 +01003270
Matt Porter403d1942005-11-29 15:00:51 +01003271 return 1;
3272}
3273
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003274#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info
3275
3276static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol,
3277 struct snd_ctl_elem_value *ucontrol)
3278{
3279 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3280 struct sigmatel_spec *spec = codec->spec;
3281
3282 ucontrol->value.integer.value[0] = spec->clfe_swap;
3283 return 0;
3284}
3285
3286static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
3287 struct snd_ctl_elem_value *ucontrol)
3288{
3289 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3290 struct sigmatel_spec *spec = codec->spec;
3291 hda_nid_t nid = kcontrol->private_value & 0xff;
Takashi Iwai68ea7b22007-11-15 15:54:38 +01003292 unsigned int val = !!ucontrol->value.integer.value[0];
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003293
Takashi Iwai68ea7b22007-11-15 15:54:38 +01003294 if (spec->clfe_swap == val)
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003295 return 0;
3296
Takashi Iwai68ea7b22007-11-15 15:54:38 +01003297 spec->clfe_swap = val;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003298
3299 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
3300 spec->clfe_swap ? 0x4 : 0x0);
3301
3302 return 1;
3303}
3304
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003305#define STAC_CODEC_HP_SWITCH(xname) \
3306 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3307 .name = xname, \
3308 .index = 0, \
3309 .info = stac92xx_hp_switch_info, \
3310 .get = stac92xx_hp_switch_get, \
3311 .put = stac92xx_hp_switch_put, \
3312 }
3313
Matt Porter403d1942005-11-29 15:00:51 +01003314#define STAC_CODEC_IO_SWITCH(xname, xpval) \
3315 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3316 .name = xname, \
3317 .index = 0, \
3318 .info = stac92xx_io_switch_info, \
3319 .get = stac92xx_io_switch_get, \
3320 .put = stac92xx_io_switch_put, \
3321 .private_value = xpval, \
3322 }
3323
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003324#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \
3325 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3326 .name = xname, \
3327 .index = 0, \
3328 .info = stac92xx_clfe_switch_info, \
3329 .get = stac92xx_clfe_switch_get, \
3330 .put = stac92xx_clfe_switch_put, \
3331 .private_value = xpval, \
3332 }
Matt Porter403d1942005-11-29 15:00:51 +01003333
Mattc7d4b2f2005-06-27 14:59:41 +02003334enum {
3335 STAC_CTL_WIDGET_VOL,
3336 STAC_CTL_WIDGET_MUTE,
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003337 STAC_CTL_WIDGET_MUTE_BEEP,
Matthew Ranostay09a99952008-01-24 11:49:21 +01003338 STAC_CTL_WIDGET_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003339 STAC_CTL_WIDGET_HP_SWITCH,
Matt Porter403d1942005-11-29 15:00:51 +01003340 STAC_CTL_WIDGET_IO_SWITCH,
Nickolas Lloyd2fc99892009-05-15 15:33:30 +02003341 STAC_CTL_WIDGET_CLFE_SWITCH,
3342 STAC_CTL_WIDGET_DC_BIAS
Mattc7d4b2f2005-06-27 14:59:41 +02003343};
3344
Takashi Iwai2b635362011-05-02 12:33:43 +02003345static const struct snd_kcontrol_new stac92xx_control_templates[] = {
Mattc7d4b2f2005-06-27 14:59:41 +02003346 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3347 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003348 HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
Matthew Ranostay09a99952008-01-24 11:49:21 +01003349 STAC_MONO_MUX,
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003350 STAC_CODEC_HP_SWITCH(NULL),
Matt Porter403d1942005-11-29 15:00:51 +01003351 STAC_CODEC_IO_SWITCH(NULL, 0),
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003352 STAC_CODEC_CLFE_SWITCH(NULL, 0),
Nickolas Lloyd2fc99892009-05-15 15:33:30 +02003353 DC_BIAS(NULL, 0, 0),
Mattc7d4b2f2005-06-27 14:59:41 +02003354};
3355
3356/* add dynamic controls */
Takashi Iwaie3c75962009-01-23 11:57:22 +01003357static struct snd_kcontrol_new *
3358stac_control_new(struct sigmatel_spec *spec,
Takashi Iwai2b635362011-05-02 12:33:43 +02003359 const struct snd_kcontrol_new *ktemp,
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01003360 const char *name,
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003361 unsigned int subdev)
Mattc7d4b2f2005-06-27 14:59:41 +02003362{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003363 struct snd_kcontrol_new *knew;
Mattc7d4b2f2005-06-27 14:59:41 +02003364
Takashi Iwai603c4012008-07-30 15:01:44 +02003365 knew = snd_array_new(&spec->kctls);
3366 if (!knew)
Takashi Iwaie3c75962009-01-23 11:57:22 +01003367 return NULL;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003368 *knew = *ktemp;
Takashi Iwai82fe0c52005-06-30 10:54:33 +02003369 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaie3c75962009-01-23 11:57:22 +01003370 if (!knew->name) {
3371 /* roolback */
3372 memset(knew, 0, sizeof(*knew));
3373 spec->kctls.alloced--;
3374 return NULL;
3375 }
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003376 knew->subdevice = subdev;
Takashi Iwaie3c75962009-01-23 11:57:22 +01003377 return knew;
3378}
3379
Takashi Iwai62cbde12012-09-14 11:58:54 +02003380static struct snd_kcontrol_new *
3381add_control_temp(struct sigmatel_spec *spec,
3382 const struct snd_kcontrol_new *ktemp,
3383 int idx, const char *name,
3384 unsigned long val)
3385{
3386 struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
3387 HDA_SUBDEV_AMP_FLAG);
3388 if (!knew)
3389 return NULL;
3390 knew->index = idx;
3391 knew->private_value = val;
3392 return knew;
3393}
3394
Takashi Iwaie3c75962009-01-23 11:57:22 +01003395static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
Takashi Iwai2b635362011-05-02 12:33:43 +02003396 const struct snd_kcontrol_new *ktemp,
Takashi Iwaie3c75962009-01-23 11:57:22 +01003397 int idx, const char *name,
3398 unsigned long val)
3399{
Takashi Iwai62cbde12012-09-14 11:58:54 +02003400 return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;
Mattc7d4b2f2005-06-27 14:59:41 +02003401}
3402
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003403static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
3404 int type, int idx, const char *name,
3405 unsigned long val)
3406{
3407 return stac92xx_add_control_temp(spec,
3408 &stac92xx_control_templates[type],
3409 idx, name, val);
3410}
3411
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003412
3413/* add dynamic controls */
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01003414static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type,
3415 const char *name, unsigned long val)
Matthew Ranostay4682eee2008-08-15 07:43:24 +02003416{
3417 return stac92xx_add_control_idx(spec, type, 0, name, val);
3418}
3419
Takashi Iwai2b635362011-05-02 12:33:43 +02003420static const struct snd_kcontrol_new stac_input_src_temp = {
Takashi Iwaie3c75962009-01-23 11:57:22 +01003421 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3422 .name = "Input Source",
3423 .info = stac92xx_mux_enum_info,
3424 .get = stac92xx_mux_enum_get,
3425 .put = stac92xx_mux_enum_put,
3426};
3427
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003428static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
3429 hda_nid_t nid, int idx)
3430{
3431 int def_conf = snd_hda_codec_get_pincfg(codec, nid);
3432 int control = 0;
3433 struct sigmatel_spec *spec = codec->spec;
3434 char name[22];
3435
Takashi Iwai99ae28b2010-09-17 14:42:34 +02003436 if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
David Henningsson8d032a82012-10-09 12:48:40 +02003437 if (spec->headset_jack && snd_hda_get_input_pin_attr(def_conf)
3438 != INPUT_PIN_ATTR_DOCK)
3439 return 0;
Takashi Iwai47408602012-04-20 13:06:53 +02003440 if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003441 && nid == spec->line_switch)
3442 control = STAC_CTL_WIDGET_IO_SWITCH;
3443 else if (snd_hda_query_pin_caps(codec, nid)
3444 & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT))
3445 control = STAC_CTL_WIDGET_DC_BIAS;
3446 else if (nid == spec->mic_switch)
3447 control = STAC_CTL_WIDGET_IO_SWITCH;
3448 }
3449
3450 if (control) {
Takashi Iwai201e06f2011-11-16 15:33:26 +01003451 snd_hda_get_pin_label(codec, nid, &spec->autocfg,
3452 name, sizeof(name), NULL);
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003453 return stac92xx_add_control(codec->spec, control,
3454 strcat(name, " Jack Mode"), nid);
3455 }
3456
3457 return 0;
3458}
3459
Takashi Iwaie3c75962009-01-23 11:57:22 +01003460static int stac92xx_add_input_source(struct sigmatel_spec *spec)
3461{
3462 struct snd_kcontrol_new *knew;
3463 struct hda_input_mux *imux = &spec->private_imux;
3464
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02003465 if (spec->auto_mic)
3466 return 0; /* no need for input source */
Takashi Iwaie3c75962009-01-23 11:57:22 +01003467 if (!spec->num_adcs || imux->num_items <= 1)
3468 return 0; /* no need for input source control */
3469 knew = stac_control_new(spec, &stac_input_src_temp,
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01003470 stac_input_src_temp.name, 0);
Takashi Iwaie3c75962009-01-23 11:57:22 +01003471 if (!knew)
3472 return -ENOMEM;
3473 knew->count = spec->num_adcs;
3474 return 0;
3475}
3476
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003477/* check whether the line-input can be used as line-out */
3478static hda_nid_t check_line_out_switch(struct hda_codec *codec)
Matt Porter403d1942005-11-29 15:00:51 +01003479{
3480 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003481 struct auto_pin_cfg *cfg = &spec->autocfg;
3482 hda_nid_t nid;
3483 unsigned int pincap;
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003484 int i;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01003485
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003486 if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
3487 return 0;
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003488 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +02003489 if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003490 nid = cfg->inputs[i].pin;
Takashi Iwai1327a322009-03-23 13:07:47 +01003491 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003492 if (pincap & AC_PINCAP_OUT)
3493 return nid;
3494 }
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003495 }
Matt Porter403d1942005-11-29 15:00:51 +01003496 return 0;
3497}
3498
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003499static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
3500
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003501/* check whether the mic-input can be used as line-out */
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003502static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003503{
3504 struct sigmatel_spec *spec = codec->spec;
3505 struct auto_pin_cfg *cfg = &spec->autocfg;
3506 unsigned int def_conf, pincap;
Takashi Iwai86e29592010-09-09 14:50:17 +02003507 int i;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003508
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003509 *dac = 0;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003510 if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
3511 return 0;
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003512 for (i = 0; i < cfg->num_inputs; i++) {
3513 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai86e29592010-09-09 14:50:17 +02003514 if (cfg->inputs[i].type != AUTO_PIN_MIC)
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003515 continue;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003516 def_conf = snd_hda_codec_get_pincfg(codec, nid);
3517 /* some laptops have an internal analog microphone
3518 * which can't be used as a output */
Takashi Iwai99ae28b2010-09-17 14:42:34 +02003519 if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003520 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003521 if (pincap & AC_PINCAP_OUT) {
3522 *dac = get_unassigned_dac(codec, nid);
3523 if (*dac)
3524 return nid;
3525 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003526 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003527 }
3528 return 0;
3529}
Steve Longerbeam7b043892007-05-03 20:50:03 +02003530
3531static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
3532{
3533 int i;
3534
3535 for (i = 0; i < spec->multiout.num_dacs; i++) {
3536 if (spec->multiout.dac_nids[i] == nid)
3537 return 1;
3538 }
3539
3540 return 0;
3541}
3542
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003543static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
3544{
3545 int i;
3546 if (is_in_dac_nids(spec, nid))
3547 return 1;
3548 for (i = 0; i < spec->autocfg.hp_outs; i++)
3549 if (spec->hp_dacs[i] == nid)
3550 return 1;
3551 for (i = 0; i < spec->autocfg.speaker_outs; i++)
3552 if (spec->speaker_dacs[i] == nid)
3553 return 1;
3554 return 0;
3555}
3556
3557static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
3558{
3559 struct sigmatel_spec *spec = codec->spec;
David Henningsson48718ea2011-10-05 09:49:05 +02003560 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003561 int j, conn_len;
David Henningsson48718ea2011-10-05 09:49:05 +02003562 hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003563 unsigned int wcaps, wtype;
3564
3565 conn_len = snd_hda_get_connections(codec, nid, conn,
3566 HDA_MAX_CONNECTIONS);
Charles Chin36706002010-01-29 12:05:51 +01003567 /* 92HD88: trace back up the link of nids to find the DAC */
3568 while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0]))
3569 != AC_WID_AUD_OUT)) {
3570 nid = conn[0];
3571 conn_len = snd_hda_get_connections(codec, nid, conn,
3572 HDA_MAX_CONNECTIONS);
3573 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003574 for (j = 0; j < conn_len; j++) {
Takashi Iwai14bafe32009-03-23 16:35:39 +01003575 wcaps = get_wcaps(codec, conn[j]);
Takashi Iwaia22d5432009-07-27 12:54:26 +02003576 wtype = get_wcaps_type(wcaps);
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003577 /* we check only analog outputs */
3578 if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL))
3579 continue;
3580 /* if this route has a free DAC, assign it */
3581 if (!check_all_dac_nids(spec, conn[j])) {
3582 if (conn_len > 1) {
3583 /* select this DAC in the pin's input mux */
3584 snd_hda_codec_write_cache(codec, nid, 0,
3585 AC_VERB_SET_CONNECT_SEL, j);
3586 }
3587 return conn[j];
3588 }
3589 }
David Henningsson48718ea2011-10-05 09:49:05 +02003590
3591 /* if all DACs are already assigned, connect to the primary DAC,
3592 unless we're assigning a secondary headphone */
3593 fallback_dac = spec->multiout.dac_nids[0];
3594 if (spec->multiout.hp_nid) {
3595 for (j = 0; j < cfg->hp_outs; j++)
3596 if (cfg->hp_pins[j] == nid) {
3597 fallback_dac = spec->multiout.hp_nid;
3598 break;
3599 }
3600 }
3601
Takashi Iwaiee58a7c2009-03-06 12:00:24 +01003602 if (conn_len > 1) {
3603 for (j = 0; j < conn_len; j++) {
David Henningsson48718ea2011-10-05 09:49:05 +02003604 if (conn[j] == fallback_dac) {
Takashi Iwaiee58a7c2009-03-06 12:00:24 +01003605 snd_hda_codec_write_cache(codec, nid, 0,
3606 AC_VERB_SET_CONNECT_SEL, j);
3607 break;
3608 }
3609 }
3610 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003611 return 0;
3612}
3613
3614static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
3615static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid);
3616
Matt Porter3cc08dc2006-01-23 15:27:49 +01003617/*
Steve Longerbeam7b043892007-05-03 20:50:03 +02003618 * Fill in the dac_nids table from the parsed pin configuration
3619 * This function only works when every pin in line_out_pins[]
3620 * contains atleast one DAC in its connection list. Some 92xx
3621 * codecs are not connected directly to a DAC, such as the 9200
3622 * and 9202/925x. For those, dac_nids[] must be hard-coded.
Matt Porter3cc08dc2006-01-23 15:27:49 +01003623 */
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003624static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
Mattc7d4b2f2005-06-27 14:59:41 +02003625{
3626 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003627 struct auto_pin_cfg *cfg = &spec->autocfg;
3628 int i;
3629 hda_nid_t nid, dac;
Steve Longerbeam7b043892007-05-03 20:50:03 +02003630
Mattc7d4b2f2005-06-27 14:59:41 +02003631 for (i = 0; i < cfg->line_outs; i++) {
3632 nid = cfg->line_out_pins[i];
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003633 dac = get_unassigned_dac(codec, nid);
3634 if (!dac) {
Takashi Iwaidf802952007-07-02 19:18:00 +02003635 if (spec->multiout.num_dacs > 0) {
3636 /* we have already working output pins,
3637 * so let's drop the broken ones again
3638 */
3639 cfg->line_outs = spec->multiout.num_dacs;
3640 break;
3641 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02003642 /* error out, no available DAC found */
3643 snd_printk(KERN_ERR
3644 "%s: No available DAC for pin 0x%x\n",
3645 __func__, nid);
3646 return -ENODEV;
3647 }
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003648 add_spec_dacs(spec, dac);
3649 }
Steve Longerbeam7b043892007-05-03 20:50:03 +02003650
Takashi Iwai139e0712009-03-06 12:10:41 +01003651 for (i = 0; i < cfg->hp_outs; i++) {
3652 nid = cfg->hp_pins[i];
3653 dac = get_unassigned_dac(codec, nid);
3654 if (dac) {
3655 if (!spec->multiout.hp_nid)
3656 spec->multiout.hp_nid = dac;
3657 else
3658 add_spec_extra_dacs(spec, dac);
3659 }
3660 spec->hp_dacs[i] = dac;
3661 }
3662
3663 for (i = 0; i < cfg->speaker_outs; i++) {
3664 nid = cfg->speaker_pins[i];
3665 dac = get_unassigned_dac(codec, nid);
3666 if (dac)
3667 add_spec_extra_dacs(spec, dac);
3668 spec->speaker_dacs[i] = dac;
3669 }
3670
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003671 /* add line-in as output */
3672 nid = check_line_out_switch(codec);
3673 if (nid) {
3674 dac = get_unassigned_dac(codec, nid);
3675 if (dac) {
3676 snd_printdd("STAC: Add line-in 0x%x as output %d\n",
3677 nid, cfg->line_outs);
3678 cfg->line_out_pins[cfg->line_outs] = nid;
3679 cfg->line_outs++;
3680 spec->line_switch = nid;
3681 add_spec_dacs(spec, dac);
3682 }
3683 }
3684 /* add mic as output */
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003685 nid = check_mic_out_switch(codec, &dac);
3686 if (nid && dac) {
3687 snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
3688 nid, cfg->line_outs);
3689 cfg->line_out_pins[cfg->line_outs] = nid;
3690 cfg->line_outs++;
3691 spec->mic_switch = nid;
3692 add_spec_dacs(spec, dac);
Mattc7d4b2f2005-06-27 14:59:41 +02003693 }
3694
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003695 snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
Steve Longerbeam7b043892007-05-03 20:50:03 +02003696 spec->multiout.num_dacs,
3697 spec->multiout.dac_nids[0],
3698 spec->multiout.dac_nids[1],
3699 spec->multiout.dac_nids[2],
3700 spec->multiout.dac_nids[3],
3701 spec->multiout.dac_nids[4]);
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003702
Mattc7d4b2f2005-06-27 14:59:41 +02003703 return 0;
3704}
3705
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003706/* create volume control/switch for the given prefx type */
Takashi Iwai668b9652009-03-06 10:13:24 +01003707static int create_controls_idx(struct hda_codec *codec, const char *pfx,
3708 int idx, hda_nid_t nid, int chs)
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003709{
Takashi Iwai7c7767e2009-01-20 15:28:38 +01003710 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003711 char name[32];
3712 int err;
3713
Takashi Iwai7c7767e2009-01-20 15:28:38 +01003714 if (!spec->check_volume_offset) {
3715 unsigned int caps, step, nums, db_scale;
3716 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3717 step = (caps & AC_AMPCAP_STEP_SIZE) >>
3718 AC_AMPCAP_STEP_SIZE_SHIFT;
3719 step = (step + 1) * 25; /* in .01dB unit */
3720 nums = (caps & AC_AMPCAP_NUM_STEPS) >>
3721 AC_AMPCAP_NUM_STEPS_SHIFT;
3722 db_scale = nums * step;
3723 /* if dB scale is over -64dB, and finer enough,
3724 * let's reduce it to half
3725 */
3726 if (db_scale > 6400 && nums >= 0x1f)
3727 spec->volume_offset = nums / 2;
3728 spec->check_volume_offset = 1;
3729 }
3730
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003731 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwai668b9652009-03-06 10:13:24 +01003732 err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name,
Takashi Iwai7c7767e2009-01-20 15:28:38 +01003733 HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
3734 spec->volume_offset));
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003735 if (err < 0)
3736 return err;
3737 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwai668b9652009-03-06 10:13:24 +01003738 err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name,
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003739 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
3740 if (err < 0)
3741 return err;
3742 return 0;
3743}
3744
Takashi Iwai668b9652009-03-06 10:13:24 +01003745#define create_controls(codec, pfx, nid, chs) \
3746 create_controls_idx(codec, pfx, 0, nid, chs)
3747
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003748static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
3749{
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003750 if (spec->multiout.num_dacs > 4) {
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003751 printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid);
3752 return 1;
3753 } else {
Takashi Iwaidda14412011-05-02 11:29:30 +02003754 snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids);
3755 spec->dac_nids[spec->multiout.num_dacs] = nid;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003756 spec->multiout.num_dacs++;
3757 }
3758 return 0;
3759}
3760
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003761static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid)
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003762{
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01003763 int i;
3764 for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) {
3765 if (!spec->multiout.extra_out_nid[i]) {
3766 spec->multiout.extra_out_nid[i] = nid;
3767 return 0;
3768 }
3769 }
3770 printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid);
3771 return 1;
Matthew Ranostayae0afd82008-02-22 17:55:05 +01003772}
3773
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003774/* Create output controls
3775 * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT)
3776 */
3777static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
3778 const hda_nid_t *pins,
3779 const hda_nid_t *dac_nids,
3780 int type)
Mattc7d4b2f2005-06-27 14:59:41 +02003781{
Takashi Iwai76624532008-12-19 10:09:47 +01003782 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +01003783 static const char * const chname[4] = {
Takashi Iwai19039bd2006-06-28 15:52:16 +02003784 "Front", "Surround", NULL /*CLFE*/, "Side"
3785 };
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003786 hda_nid_t nid;
Takashi Iwai91589232008-12-19 15:59:40 +01003787 int i, err;
3788 unsigned int wid_caps;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003789
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003790 for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
Takashi Iwaiffd0e562009-04-16 12:20:24 +02003791 if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
Takashi Iwaie35d9d62011-05-17 11:28:16 +02003792 if (is_jack_detectable(codec, pins[i]))
Takashi Iwaiffd0e562009-04-16 12:20:24 +02003793 spec->hp_detect = 1;
3794 }
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003795 nid = dac_nids[i];
3796 if (!nid)
3797 continue;
3798 if (type != AUTO_PIN_HP_OUT && i == 2) {
Mattc7d4b2f2005-06-27 14:59:41 +02003799 /* Center/LFE */
Takashi Iwai7c7767e2009-01-20 15:28:38 +01003800 err = create_controls(codec, "Center", nid, 1);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003801 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003802 return err;
Takashi Iwai7c7767e2009-01-20 15:28:38 +01003803 err = create_controls(codec, "LFE", nid, 2);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003804 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003805 return err;
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02003806
3807 wid_caps = get_wcaps(codec, nid);
3808
3809 if (wid_caps & AC_WCAP_LR_SWAP) {
3810 err = stac92xx_add_control(spec,
3811 STAC_CTL_WIDGET_CLFE_SWITCH,
3812 "Swap Center/LFE Playback Switch", nid);
3813
3814 if (err < 0)
3815 return err;
3816 }
3817
Mattc7d4b2f2005-06-27 14:59:41 +02003818 } else {
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003819 const char *name;
Takashi Iwai668b9652009-03-06 10:13:24 +01003820 int idx;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003821 switch (type) {
3822 case AUTO_PIN_HP_OUT:
Takashi Iwai668b9652009-03-06 10:13:24 +01003823 name = "Headphone";
3824 idx = i;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003825 break;
3826 case AUTO_PIN_SPEAKER_OUT:
Takashi Iwaif37bc7a2012-11-08 15:59:23 +01003827 if (num_outs <= 2) {
3828 name = i ? "Bass Speaker" : "Speaker";
3829 idx = 0;
David Henningsson298efee2012-09-06 11:17:58 +02003830 break;
3831 }
3832 /* Fall through in case of multi speaker outs */
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003833 default:
3834 name = chname[i];
Takashi Iwai668b9652009-03-06 10:13:24 +01003835 idx = 0;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003836 break;
Takashi Iwai76624532008-12-19 10:09:47 +01003837 }
Takashi Iwai668b9652009-03-06 10:13:24 +01003838 err = create_controls_idx(codec, name, idx, nid, 3);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003839 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02003840 return err;
3841 }
3842 }
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003843 return 0;
3844}
3845
Takashi Iwai62cbde12012-09-14 11:58:54 +02003846static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
3847 unsigned int dir_mask, unsigned int data);
3848
3849/* hook for controlling mic-mute LED GPIO */
3850static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol,
3851 struct snd_ctl_elem_value *ucontrol)
3852{
3853 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3854 struct sigmatel_spec *spec = codec->spec;
3855 int err;
3856 bool mute;
3857
3858 err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3859 if (err <= 0)
3860 return err;
3861 mute = !(ucontrol->value.integer.value[0] &&
3862 ucontrol->value.integer.value[1]);
3863 if (spec->mic_mute_led_on != mute) {
3864 spec->mic_mute_led_on = mute;
3865 if (mute)
3866 spec->gpio_data |= spec->mic_mute_led_gpio;
3867 else
3868 spec->gpio_data &= ~spec->mic_mute_led_gpio;
3869 stac_gpio_set(codec, spec->gpio_mask,
3870 spec->gpio_dir, spec->gpio_data);
3871 }
3872 return err;
3873}
3874
Takashi Iwai6479c632009-07-28 18:20:25 +02003875static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
3876 unsigned long sw, int idx)
3877{
Takashi Iwai62cbde12012-09-14 11:58:54 +02003878 struct sigmatel_spec *spec = codec->spec;
3879 struct snd_kcontrol_new *knew;
Takashi Iwai6479c632009-07-28 18:20:25 +02003880 int err;
Takashi Iwai62cbde12012-09-14 11:58:54 +02003881
Takashi Iwai6479c632009-07-28 18:20:25 +02003882 err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
Takashi Iwaibf677bd2009-07-30 09:24:29 +02003883 "Capture Volume", vol);
Takashi Iwai6479c632009-07-28 18:20:25 +02003884 if (err < 0)
3885 return err;
Takashi Iwai62cbde12012-09-14 11:58:54 +02003886
3887 knew = add_control_temp(spec,
3888 &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE],
3889 idx, "Capture Switch", sw);
3890 if (!knew)
3891 return -ENOMEM;
3892 /* add a LED hook for some HP laptops */
3893 if (spec->mic_mute_led_gpio)
3894 knew->put = stac92xx_capture_sw_put_led;
3895
Takashi Iwai6479c632009-07-28 18:20:25 +02003896 return 0;
3897}
3898
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003899/* add playback controls from the parsed DAC table */
3900static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
3901 const struct auto_pin_cfg *cfg)
3902{
3903 struct sigmatel_spec *spec = codec->spec;
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003904 hda_nid_t nid;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003905 int err;
Nickolas Lloyd7c922de2009-06-01 11:12:29 +02003906 int idx;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003907
3908 err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins,
3909 spec->multiout.dac_nids,
3910 cfg->line_out_type);
3911 if (err < 0)
3912 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02003913
Takashi Iwaia9cb5c92008-11-24 07:51:11 +01003914 if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) {
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003915 err = stac92xx_add_control(spec,
3916 STAC_CTL_WIDGET_HP_SWITCH,
Takashi Iwaid7a89432008-11-12 09:48:04 +01003917 "Headphone as Line Out Switch",
3918 cfg->hp_pins[cfg->hp_outs - 1]);
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02003919 if (err < 0)
3920 return err;
3921 }
3922
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003923 for (idx = 0; idx < cfg->num_inputs; idx++) {
Takashi Iwai86e29592010-09-09 14:50:17 +02003924 if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
Takashi Iwaieea7dc92010-08-30 13:06:15 +02003925 break;
3926 nid = cfg->inputs[idx].pin;
3927 err = stac92xx_add_jack_mode_control(codec, nid, idx);
3928 if (err < 0)
3929 return err;
Matthew Ranostayb5895dc2008-01-25 15:24:50 +01003930 }
Matt Porter403d1942005-11-29 15:00:51 +01003931
Mattc7d4b2f2005-06-27 14:59:41 +02003932 return 0;
3933}
3934
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003935/* add playback controls for Speaker and HP outputs */
3936static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
3937 struct auto_pin_cfg *cfg)
Mattc7d4b2f2005-06-27 14:59:41 +02003938{
3939 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003940 int err;
Mattc7d4b2f2005-06-27 14:59:41 +02003941
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01003942 err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins,
3943 spec->hp_dacs, AUTO_PIN_HP_OUT);
3944 if (err < 0)
3945 return err;
3946
3947 err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins,
3948 spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT);
3949 if (err < 0)
3950 return err;
3951
Mattc7d4b2f2005-06-27 14:59:41 +02003952 return 0;
3953}
3954
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003955/* labels for mono mux outputs */
Takashi Iwaiea734962011-01-17 11:29:34 +01003956static const char * const stac92xx_mono_labels[4] = {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02003957 "DAC0", "DAC1", "Mixer", "DAC2"
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003958};
3959
3960/* create mono mux for mono out on capable codecs */
3961static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
3962{
3963 struct sigmatel_spec *spec = codec->spec;
3964 struct hda_input_mux *mono_mux = &spec->private_mono_mux;
3965 int i, num_cons;
3966 hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
3967
3968 num_cons = snd_hda_get_connections(codec,
3969 spec->mono_nid,
3970 con_lst,
3971 HDA_MAX_NUM_INPUTS);
Jaroslav Kysela16a433d2009-07-22 16:20:40 +02003972 if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003973 return -EINVAL;
3974
Takashi Iwai10a20af2010-09-09 16:28:02 +02003975 for (i = 0; i < num_cons; i++)
3976 snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
3977 NULL);
Matthew Ranostay09a99952008-01-24 11:49:21 +01003978
3979 return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
3980 "Mono Mux", spec->mono_nid);
Matthew Ranostayb22b4822008-01-22 12:32:30 +01003981}
3982
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003983/* create PC beep volume controls */
3984static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3985 hda_nid_t nid)
3986{
3987 struct sigmatel_spec *spec = codec->spec;
3988 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003989 int err, type = STAC_CTL_WIDGET_MUTE_BEEP;
3990
3991 if (spec->anabeep_nid == nid)
3992 type = STAC_CTL_WIDGET_MUTE;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003993
3994 /* check for mute support for the the amp */
3995 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003996 err = stac92xx_add_control(spec, type,
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01003997 "Beep Playback Switch",
Matthew Ranostay1cd22242008-07-18 18:20:52 +02003998 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3999 if (err < 0)
4000 return err;
4001 }
4002
4003 /* check to see if there is volume support for the amp */
4004 if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
4005 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01004006 "Beep Playback Volume",
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004007 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
4008 if (err < 0)
4009 return err;
4010 }
4011 return 0;
4012}
4013
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01004014#ifdef CONFIG_SND_HDA_INPUT_BEEP
4015#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info
4016
4017static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
4018 struct snd_ctl_elem_value *ucontrol)
4019{
4020 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4021 ucontrol->value.integer.value[0] = codec->beep->enabled;
4022 return 0;
4023}
4024
4025static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
4026 struct snd_ctl_elem_value *ucontrol)
4027{
4028 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02004029 return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01004030}
4031
Takashi Iwai2b635362011-05-02 12:33:43 +02004032static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01004033 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4034 .info = stac92xx_dig_beep_switch_info,
4035 .get = stac92xx_dig_beep_switch_get,
4036 .put = stac92xx_dig_beep_switch_put,
4037};
4038
4039static int stac92xx_beep_switch_ctl(struct hda_codec *codec)
4040{
4041 return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl,
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01004042 0, "Beep Playback Switch", 0);
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01004043}
4044#endif
4045
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004046static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
4047{
4048 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai667067d2009-08-13 18:14:42 +02004049 int i, j, err = 0;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004050
4051 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai667067d2009-08-13 18:14:42 +02004052 hda_nid_t nid;
4053 unsigned int wcaps;
4054 unsigned long val;
4055
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004056 nid = spec->mux_nids[i];
4057 wcaps = get_wcaps(codec, nid);
Takashi Iwai667067d2009-08-13 18:14:42 +02004058 if (!(wcaps & AC_WCAP_OUT_AMP))
4059 continue;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004060
Takashi Iwai667067d2009-08-13 18:14:42 +02004061 /* check whether already the same control was created as
4062 * normal Capture Volume.
4063 */
4064 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4065 for (j = 0; j < spec->num_caps; j++) {
4066 if (spec->capvols[j] == val)
4067 break;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004068 }
Takashi Iwai667067d2009-08-13 18:14:42 +02004069 if (j < spec->num_caps)
4070 continue;
4071
4072 err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i,
4073 "Mux Capture Volume", val);
4074 if (err < 0)
4075 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004076 }
4077 return 0;
4078};
4079
Takashi Iwaiea734962011-01-17 11:29:34 +01004080static const char * const stac92xx_spdif_labels[3] = {
Matthew Ranostay65973632008-09-16 10:39:37 -04004081 "Digital Playback", "Analog Mux 1", "Analog Mux 2",
Matthew Ranostayd9737752008-09-07 12:03:41 +02004082};
4083
4084static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
4085{
4086 struct sigmatel_spec *spec = codec->spec;
4087 struct hda_input_mux *spdif_mux = &spec->private_smux;
Takashi Iwaiea734962011-01-17 11:29:34 +01004088 const char * const *labels = spec->spdif_labels;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004089 int i, num_cons;
Matthew Ranostay65973632008-09-16 10:39:37 -04004090 hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
Matthew Ranostayd9737752008-09-07 12:03:41 +02004091
4092 num_cons = snd_hda_get_connections(codec,
4093 spec->smux_nids[0],
4094 con_lst,
4095 HDA_MAX_NUM_INPUTS);
Jaroslav Kysela16a433d2009-07-22 16:20:40 +02004096 if (num_cons <= 0)
Matthew Ranostayd9737752008-09-07 12:03:41 +02004097 return -EINVAL;
4098
Matthew Ranostay65973632008-09-16 10:39:37 -04004099 if (!labels)
4100 labels = stac92xx_spdif_labels;
4101
Takashi Iwai10a20af2010-09-09 16:28:02 +02004102 for (i = 0; i < num_cons; i++)
4103 snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
Matthew Ranostayd9737752008-09-07 12:03:41 +02004104
4105 return 0;
4106}
4107
Matt Porter8b657272006-10-26 17:12:59 +02004108/* labels for dmic mux inputs */
Takashi Iwaiea734962011-01-17 11:29:34 +01004109static const char * const stac92xx_dmic_labels[5] = {
Matt Porter8b657272006-10-26 17:12:59 +02004110 "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
4111 "Digital Mic 3", "Digital Mic 4"
4112};
4113
Vitaliy Kulikov699d8992011-03-10 13:43:35 -06004114static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
4115 int idx)
4116{
4117 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
4118 int nums;
4119 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
4120 if (idx >= 0 && idx < nums)
4121 return conn[idx];
4122 return 0;
4123}
4124
Takashi Iwai8d087c72011-06-28 12:45:47 +02004125/* look for NID recursively */
4126#define get_connection_index(codec, mux, nid) \
4127 snd_hda_get_conn_index(codec, mux, nid, 1)
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004128
Takashi Iwai667067d2009-08-13 18:14:42 +02004129/* create a volume assigned to the given pin (only if supported) */
Takashi Iwai96f845d2009-08-29 00:49:36 +02004130/* return 1 if the volume control is created */
Takashi Iwai667067d2009-08-13 18:14:42 +02004131static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004132 const char *label, int idx, int direction)
Takashi Iwai667067d2009-08-13 18:14:42 +02004133{
4134 unsigned int caps, nums;
4135 char name[32];
Takashi Iwai96f845d2009-08-29 00:49:36 +02004136 int err;
Takashi Iwai667067d2009-08-13 18:14:42 +02004137
Takashi Iwai96f845d2009-08-29 00:49:36 +02004138 if (direction == HDA_OUTPUT)
4139 caps = AC_WCAP_OUT_AMP;
4140 else
4141 caps = AC_WCAP_IN_AMP;
4142 if (!(get_wcaps(codec, nid) & caps))
Takashi Iwai667067d2009-08-13 18:14:42 +02004143 return 0;
Takashi Iwai96f845d2009-08-29 00:49:36 +02004144 caps = query_amp_caps(codec, nid, direction);
Takashi Iwai667067d2009-08-13 18:14:42 +02004145 nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
4146 if (!nums)
4147 return 0;
4148 snprintf(name, sizeof(name), "%s Capture Volume", label);
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004149 err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
4150 HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
Takashi Iwai96f845d2009-08-29 00:49:36 +02004151 if (err < 0)
4152 return err;
4153 return 1;
Takashi Iwai667067d2009-08-13 18:14:42 +02004154}
4155
Matt Porter8b657272006-10-26 17:12:59 +02004156/* create playback/capture controls for input pins on dmic capable codecs */
4157static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
4158 const struct auto_pin_cfg *cfg)
4159{
4160 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai5207e102009-07-30 13:09:08 +02004161 struct hda_input_mux *imux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02004162 struct hda_input_mux *dimux = &spec->private_dimux;
Vitaliy Kulikov263d0322010-09-08 08:56:03 +02004163 int err, i;
Takashi Iwai5207e102009-07-30 13:09:08 +02004164 unsigned int def_conf;
Matt Porter8b657272006-10-26 17:12:59 +02004165
Takashi Iwai10a20af2010-09-09 16:28:02 +02004166 snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
Takashi Iwai5207e102009-07-30 13:09:08 +02004167
Matt Porter8b657272006-10-26 17:12:59 +02004168 for (i = 0; i < spec->num_dmics; i++) {
Matthew Ranostay0678acc2008-01-08 12:10:50 +01004169 hda_nid_t nid;
Takashi Iwai10a20af2010-09-09 16:28:02 +02004170 int index, type_idx;
Takashi Iwai201e06f2011-11-16 15:33:26 +01004171 char label[32];
Matt Porter8b657272006-10-26 17:12:59 +02004172
Takashi Iwai667067d2009-08-13 18:14:42 +02004173 nid = spec->dmic_nids[i];
4174 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
4175 continue;
4176 def_conf = snd_hda_codec_get_pincfg(codec, nid);
Matt Porter8b657272006-10-26 17:12:59 +02004177 if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
4178 continue;
4179
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004180 index = get_connection_index(codec, spec->dmux_nids[0], nid);
4181 if (index < 0)
4182 continue;
4183
Takashi Iwai201e06f2011-11-16 15:33:26 +01004184 snd_hda_get_pin_label(codec, nid, &spec->autocfg,
4185 label, sizeof(label), NULL);
Takashi Iwai10a20af2010-09-09 16:28:02 +02004186 snd_hda_add_imux_item(dimux, label, index, &type_idx);
Takashi Iwai2d7ec122010-12-23 10:16:05 +01004187 if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
4188 snd_hda_add_imux_item(imux, label, index, &type_idx);
Takashi Iwai5207e102009-07-30 13:09:08 +02004189
Takashi Iwai10a20af2010-09-09 16:28:02 +02004190 err = create_elem_capture_vol(codec, nid, label, type_idx,
4191 HDA_INPUT);
Takashi Iwai667067d2009-08-13 18:14:42 +02004192 if (err < 0)
4193 return err;
Takashi Iwai96f845d2009-08-29 00:49:36 +02004194 if (!err) {
4195 err = create_elem_capture_vol(codec, nid, label,
Takashi Iwai10a20af2010-09-09 16:28:02 +02004196 type_idx, HDA_OUTPUT);
Takashi Iwai96f845d2009-08-29 00:49:36 +02004197 if (err < 0)
4198 return err;
Vitaliy Kulikov699d8992011-03-10 13:43:35 -06004199 if (!err) {
4200 nid = get_connected_node(codec,
4201 spec->dmux_nids[0], index);
4202 if (nid)
4203 err = create_elem_capture_vol(codec,
4204 nid, label,
4205 type_idx, HDA_INPUT);
4206 if (err < 0)
4207 return err;
4208 }
Takashi Iwai96f845d2009-08-29 00:49:36 +02004209 }
Matt Porter8b657272006-10-26 17:12:59 +02004210 }
4211
4212 return 0;
4213}
4214
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004215static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
Charles Chin99077902010-09-17 10:22:32 +02004216 hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004217{
4218 unsigned int cfg;
Takashi Iwai1f83ac52011-05-17 12:29:09 +02004219 unsigned int type;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004220
4221 if (!nid)
4222 return 0;
4223 cfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai1f83ac52011-05-17 12:29:09 +02004224 type = get_defcfg_device(cfg);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02004225 switch (snd_hda_get_input_pin_attr(cfg)) {
4226 case INPUT_PIN_ATTR_INT:
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004227 if (*fixed)
4228 return 1; /* already occupied */
Takashi Iwai1f83ac52011-05-17 12:29:09 +02004229 if (type != AC_JACK_MIC_IN)
4230 return 1; /* invalid type */
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004231 *fixed = nid;
4232 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02004233 case INPUT_PIN_ATTR_UNUSED:
4234 break;
4235 case INPUT_PIN_ATTR_DOCK:
4236 if (*dock)
4237 return 1; /* already occupied */
Takashi Iwai1f83ac52011-05-17 12:29:09 +02004238 if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN)
4239 return 1; /* invalid type */
Takashi Iwai99ae28b2010-09-17 14:42:34 +02004240 *dock = nid;
4241 break;
4242 default:
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004243 if (*ext)
4244 return 1; /* already occupied */
Takashi Iwai1f83ac52011-05-17 12:29:09 +02004245 if (type != AC_JACK_MIC_IN)
4246 return 1; /* invalid type */
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004247 *ext = nid;
4248 break;
4249 }
4250 return 0;
4251}
4252
4253static int set_mic_route(struct hda_codec *codec,
4254 struct sigmatel_mic_route *mic,
4255 hda_nid_t pin)
4256{
4257 struct sigmatel_spec *spec = codec->spec;
4258 struct auto_pin_cfg *cfg = &spec->autocfg;
4259 int i;
4260
4261 mic->pin = pin;
Charles Chin99077902010-09-17 10:22:32 +02004262 if (pin == 0)
4263 return 0;
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004264 for (i = 0; i < cfg->num_inputs; i++) {
4265 if (pin == cfg->inputs[i].pin)
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004266 break;
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004267 }
Takashi Iwai86e29592010-09-09 14:50:17 +02004268 if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004269 /* analog pin */
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004270 i = get_connection_index(codec, spec->mux_nids[0], pin);
4271 if (i < 0)
4272 return -1;
4273 mic->mux_idx = i;
Takashi Iwai02d33322009-10-01 16:38:11 +02004274 mic->dmux_idx = -1;
4275 if (spec->dmux_nids)
4276 mic->dmux_idx = get_connection_index(codec,
4277 spec->dmux_nids[0],
4278 spec->mux_nids[0]);
Takashi Iwaida2a2aa2009-08-10 07:44:09 +02004279 } else if (spec->dmux_nids) {
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004280 /* digital pin */
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004281 i = get_connection_index(codec, spec->dmux_nids[0], pin);
4282 if (i < 0)
4283 return -1;
4284 mic->dmux_idx = i;
Takashi Iwai02d33322009-10-01 16:38:11 +02004285 mic->mux_idx = -1;
4286 if (spec->mux_nids)
4287 mic->mux_idx = get_connection_index(codec,
4288 spec->mux_nids[0],
4289 spec->dmux_nids[0]);
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004290 }
4291 return 0;
4292}
4293
4294/* return non-zero if the device is for automatic mic switch */
4295static int stac_check_auto_mic(struct hda_codec *codec)
4296{
4297 struct sigmatel_spec *spec = codec->spec;
4298 struct auto_pin_cfg *cfg = &spec->autocfg;
Charles Chin99077902010-09-17 10:22:32 +02004299 hda_nid_t fixed, ext, dock;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004300 int i;
4301
Charles Chin99077902010-09-17 10:22:32 +02004302 fixed = ext = dock = 0;
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004303 for (i = 0; i < cfg->num_inputs; i++)
Charles Chin99077902010-09-17 10:22:32 +02004304 if (check_mic_pin(codec, cfg->inputs[i].pin,
4305 &fixed, &ext, &dock))
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004306 return 0;
4307 for (i = 0; i < spec->num_dmics; i++)
Charles Chin99077902010-09-17 10:22:32 +02004308 if (check_mic_pin(codec, spec->dmic_nids[i],
4309 &fixed, &ext, &dock))
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004310 return 0;
Takashi Iwai80c67852011-01-13 08:08:08 +01004311 if (!fixed || (!ext && !dock))
Charles Chin99077902010-09-17 10:22:32 +02004312 return 0; /* no input to switch */
Takashi Iwaie35d9d62011-05-17 11:28:16 +02004313 if (!is_jack_detectable(codec, ext))
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004314 return 0; /* no unsol support */
4315 if (set_mic_route(codec, &spec->ext_mic, ext) ||
Charles Chin99077902010-09-17 10:22:32 +02004316 set_mic_route(codec, &spec->int_mic, fixed) ||
4317 set_mic_route(codec, &spec->dock_mic, dock))
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004318 return 0; /* something is wrong */
4319 return 1;
4320}
4321
Mattc7d4b2f2005-06-27 14:59:41 +02004322/* create playback/capture controls for input pins */
4323static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
4324{
4325 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02004326 struct hda_input_mux *imux = &spec->private_imux;
Takashi Iwai667067d2009-08-13 18:14:42 +02004327 int i, j;
Vitaliy Kulikov263d0322010-09-08 08:56:03 +02004328 const char *label;
Mattc7d4b2f2005-06-27 14:59:41 +02004329
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004330 for (i = 0; i < cfg->num_inputs; i++) {
4331 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02004332 int index, err, type_idx;
Mattc7d4b2f2005-06-27 14:59:41 +02004333
Takashi Iwai314634b2006-09-21 11:56:18 +02004334 index = -1;
4335 for (j = 0; j < spec->num_muxes; j++) {
Takashi Iwai667067d2009-08-13 18:14:42 +02004336 index = get_connection_index(codec, spec->mux_nids[j],
4337 nid);
4338 if (index >= 0)
4339 break;
Mattc7d4b2f2005-06-27 14:59:41 +02004340 }
Takashi Iwai667067d2009-08-13 18:14:42 +02004341 if (index < 0)
4342 continue;
4343
Takashi Iwai10a20af2010-09-09 16:28:02 +02004344 label = hda_get_autocfg_input_label(codec, cfg, i);
4345 snd_hda_add_imux_item(imux, label, index, &type_idx);
Vitaliy Kulikov263d0322010-09-08 08:56:03 +02004346
Takashi Iwai667067d2009-08-13 18:14:42 +02004347 err = create_elem_capture_vol(codec, nid,
Vitaliy Kulikov263d0322010-09-08 08:56:03 +02004348 label, type_idx,
Takashi Iwai96f845d2009-08-29 00:49:36 +02004349 HDA_INPUT);
Takashi Iwai667067d2009-08-13 18:14:42 +02004350 if (err < 0)
4351 return err;
Mattc7d4b2f2005-06-27 14:59:41 +02004352 }
Takashi Iwai5207e102009-07-30 13:09:08 +02004353 spec->num_analog_muxes = imux->num_items;
Mattc7d4b2f2005-06-27 14:59:41 +02004354
Steve Longerbeam7b043892007-05-03 20:50:03 +02004355 if (imux->num_items) {
Sam Revitch62fe78e2006-05-10 15:09:17 +02004356 /*
4357 * Set the current input for the muxes.
4358 * The STAC9221 has two input muxes with identical source
4359 * NID lists. Hopefully this won't get confused.
4360 */
4361 for (i = 0; i < spec->num_muxes; i++) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004362 snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0,
4363 AC_VERB_SET_CONNECT_SEL,
4364 imux->items[0].index);
Sam Revitch62fe78e2006-05-10 15:09:17 +02004365 }
4366 }
4367
Mattc7d4b2f2005-06-27 14:59:41 +02004368 return 0;
4369}
4370
Mattc7d4b2f2005-06-27 14:59:41 +02004371static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
4372{
4373 struct sigmatel_spec *spec = codec->spec;
4374 int i;
4375
4376 for (i = 0; i < spec->autocfg.line_outs; i++) {
4377 hda_nid_t nid = spec->autocfg.line_out_pins[i];
4378 stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
4379 }
4380}
4381
4382static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
4383{
4384 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004385 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02004386
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004387 for (i = 0; i < spec->autocfg.hp_outs; i++) {
4388 hda_nid_t pin;
4389 pin = spec->autocfg.hp_pins[i];
4390 if (pin) /* connect to front */
4391 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
4392 }
4393 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
4394 hda_nid_t pin;
4395 pin = spec->autocfg.speaker_pins[i];
4396 if (pin) /* connect to front */
4397 stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN);
4398 }
Mattc7d4b2f2005-06-27 14:59:41 +02004399}
4400
Takashi Iwai8af3aeb2009-11-18 14:23:37 +01004401static int is_dual_headphones(struct hda_codec *codec)
4402{
4403 struct sigmatel_spec *spec = codec->spec;
4404 int i, valid_hps;
4405
4406 if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT ||
4407 spec->autocfg.hp_outs <= 1)
4408 return 0;
4409 valid_hps = 0;
4410 for (i = 0; i < spec->autocfg.hp_outs; i++) {
4411 hda_nid_t nid = spec->autocfg.hp_pins[i];
4412 unsigned int cfg = snd_hda_codec_get_pincfg(codec, nid);
4413 if (get_defcfg_location(cfg) & AC_JACK_LOC_SEPARATE)
4414 continue;
4415 valid_hps++;
4416 }
4417 return (valid_hps > 1);
4418}
4419
4420
Charles Chin9009b0e2011-11-03 10:27:27 +01004421static int stac92xx_parse_auto_config(struct hda_codec *codec)
Mattc7d4b2f2005-06-27 14:59:41 +02004422{
4423 struct sigmatel_spec *spec = codec->spec;
Charles Chin9009b0e2011-11-03 10:27:27 +01004424 hda_nid_t dig_out = 0, dig_in = 0;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01004425 int hp_swap = 0;
Takashi Iwai6479c632009-07-28 18:20:25 +02004426 int i, err;
Mattc7d4b2f2005-06-27 14:59:41 +02004427
Matt Porter8b657272006-10-26 17:12:59 +02004428 if ((err = snd_hda_parse_pin_def_config(codec,
4429 &spec->autocfg,
4430 spec->dmic_nids)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02004431 return err;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004432 if (! spec->autocfg.line_outs)
Matt Porter869264c2006-01-25 19:20:50 +01004433 return 0; /* can't find valid pin config */
Takashi Iwai19039bd2006-06-28 15:52:16 +02004434
Jiang Zhebcecd9b2007-11-12 12:57:03 +01004435 /* If we have no real line-out pin and multiple hp-outs, HPs should
4436 * be set up as multi-channel outputs.
4437 */
Takashi Iwai8af3aeb2009-11-18 14:23:37 +01004438 if (is_dual_headphones(codec)) {
Jiang Zhebcecd9b2007-11-12 12:57:03 +01004439 /* Copy hp_outs to line_outs, backup line_outs in
4440 * speaker_outs so that the following routines can handle
4441 * HP pins as primary outputs.
4442 */
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004443 snd_printdd("stac92xx: Enabling multi-HPs workaround\n");
Jiang Zhebcecd9b2007-11-12 12:57:03 +01004444 memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
4445 sizeof(spec->autocfg.line_out_pins));
4446 spec->autocfg.speaker_outs = spec->autocfg.line_outs;
4447 memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
4448 sizeof(spec->autocfg.hp_pins));
4449 spec->autocfg.line_outs = spec->autocfg.hp_outs;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004450 spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
4451 spec->autocfg.hp_outs = 0;
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01004452 hp_swap = 1;
Jiang Zhebcecd9b2007-11-12 12:57:03 +01004453 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01004454 if (spec->autocfg.mono_out_pin) {
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004455 int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
4456 (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
Matthew Ranostay09a99952008-01-24 11:49:21 +01004457 u32 caps = query_amp_caps(codec,
4458 spec->autocfg.mono_out_pin, dir);
4459 hda_nid_t conn_list[1];
4460
4461 /* get the mixer node and then the mono mux if it exists */
4462 if (snd_hda_get_connections(codec,
4463 spec->autocfg.mono_out_pin, conn_list, 1) &&
4464 snd_hda_get_connections(codec, conn_list[0],
Jaroslav Kysela16a433d2009-07-22 16:20:40 +02004465 conn_list, 1) > 0) {
Matthew Ranostay09a99952008-01-24 11:49:21 +01004466
4467 int wcaps = get_wcaps(codec, conn_list[0]);
Takashi Iwaia22d5432009-07-27 12:54:26 +02004468 int wid_type = get_wcaps_type(wcaps);
Matthew Ranostay09a99952008-01-24 11:49:21 +01004469 /* LR swap check, some stac925x have a mux that
4470 * changes the DACs output path instead of the
4471 * mono-mux path.
4472 */
4473 if (wid_type == AC_WID_AUD_SEL &&
4474 !(wcaps & AC_WCAP_LR_SWAP))
4475 spec->mono_nid = conn_list[0];
4476 }
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004477 if (dir) {
4478 hda_nid_t nid = spec->autocfg.mono_out_pin;
4479
4480 /* most mono outs have a least a mute/unmute switch */
4481 dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
4482 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
4483 "Mono Playback Switch",
4484 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
Matthew Ranostay09a99952008-01-24 11:49:21 +01004485 if (err < 0)
4486 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004487 /* check for volume support for the amp */
4488 if ((caps & AC_AMPCAP_NUM_STEPS)
4489 >> AC_AMPCAP_NUM_STEPS_SHIFT) {
4490 err = stac92xx_add_control(spec,
4491 STAC_CTL_WIDGET_VOL,
4492 "Mono Playback Volume",
4493 HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir));
4494 if (err < 0)
4495 return err;
4496 }
Matthew Ranostay09a99952008-01-24 11:49:21 +01004497 }
4498
4499 stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
4500 AC_PINCTL_OUT_EN);
4501 }
Jiang Zhebcecd9b2007-11-12 12:57:03 +01004502
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004503 if (!spec->multiout.num_dacs) {
4504 err = stac92xx_auto_fill_dac_nids(codec);
4505 if (err < 0)
Takashi Iwai19039bd2006-06-28 15:52:16 +02004506 return err;
Takashi Iwaic9280d62009-01-15 17:31:00 +01004507 err = stac92xx_auto_create_multi_out_ctls(codec,
4508 &spec->autocfg);
4509 if (err < 0)
4510 return err;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004511 }
Mattc7d4b2f2005-06-27 14:59:41 +02004512
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004513 /* setup analog beep controls */
4514 if (spec->anabeep_nid > 0) {
4515 err = stac92xx_auto_create_beep_ctls(codec,
4516 spec->anabeep_nid);
4517 if (err < 0)
4518 return err;
4519 }
4520
4521 /* setup digital beep controls and input device */
4522#ifdef CONFIG_SND_HDA_INPUT_BEEP
4523 if (spec->digbeep_nid > 0) {
4524 hda_nid_t nid = spec->digbeep_nid;
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01004525 unsigned int caps;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004526
4527 err = stac92xx_auto_create_beep_ctls(codec, nid);
4528 if (err < 0)
4529 return err;
4530 err = snd_hda_attach_beep_device(codec, nid);
4531 if (err < 0)
4532 return err;
Takashi Iwaid8d881d2009-12-22 07:52:49 +01004533 if (codec->beep) {
4534 /* IDT/STAC codecs have linear beep tone parameter */
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01004535 codec->beep->linear_tone = spec->linear_tone_beep;
Takashi Iwaid8d881d2009-12-22 07:52:49 +01004536 /* if no beep switch is available, make its own one */
4537 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
4538 if (!(caps & AC_AMPCAP_MUTE)) {
4539 err = stac92xx_beep_switch_ctl(codec);
4540 if (err < 0)
4541 return err;
4542 }
Takashi Iwai4d4e9bb2008-11-12 16:45:04 +01004543 }
Matthew Ranostay1cd22242008-07-18 18:20:52 +02004544 }
4545#endif
4546
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02004547 err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02004548 if (err < 0)
4549 return err;
4550
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01004551 /* All output parsing done, now restore the swapped hp pins */
4552 if (hp_swap) {
4553 memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
4554 sizeof(spec->autocfg.hp_pins));
4555 spec->autocfg.hp_outs = spec->autocfg.line_outs;
4556 spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
4557 spec->autocfg.line_outs = 0;
4558 }
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02004559
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004560 if (stac_check_auto_mic(codec)) {
4561 spec->auto_mic = 1;
4562 /* only one capture for auto-mic */
4563 spec->num_adcs = 1;
4564 spec->num_caps = 1;
4565 spec->num_muxes = 1;
4566 }
4567
Takashi Iwai6479c632009-07-28 18:20:25 +02004568 for (i = 0; i < spec->num_caps; i++) {
4569 err = stac92xx_add_capvol_ctls(codec, spec->capvols[i],
4570 spec->capsws[i], i);
4571 if (err < 0)
4572 return err;
4573 }
4574
Takashi Iwaidc04d1b2009-03-06 10:00:05 +01004575 err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg);
Maxim Levitsky0fb87bb2007-09-03 15:29:04 +02004576 if (err < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02004577 return err;
4578
Matthew Ranostayb22b4822008-01-22 12:32:30 +01004579 if (spec->mono_nid > 0) {
4580 err = stac92xx_auto_create_mono_output_ctls(codec);
4581 if (err < 0)
4582 return err;
4583 }
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04004584 if (spec->num_dmics > 0 && !spec->dinput_mux)
Matt Porter8b657272006-10-26 17:12:59 +02004585 if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
4586 &spec->autocfg)) < 0)
4587 return err;
Matthew Ranostay4682eee2008-08-15 07:43:24 +02004588 if (spec->num_muxes > 0) {
4589 err = stac92xx_auto_create_mux_input_ctls(codec);
4590 if (err < 0)
4591 return err;
4592 }
Matthew Ranostayd9737752008-09-07 12:03:41 +02004593 if (spec->num_smuxes > 0) {
4594 err = stac92xx_auto_create_spdif_mux_ctls(codec);
4595 if (err < 0)
4596 return err;
4597 }
Matt Porter8b657272006-10-26 17:12:59 +02004598
Takashi Iwaie3c75962009-01-23 11:57:22 +01004599 err = stac92xx_add_input_source(spec);
4600 if (err < 0)
4601 return err;
4602
Mattc7d4b2f2005-06-27 14:59:41 +02004603 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Matt Porter403d1942005-11-29 15:00:51 +01004604 if (spec->multiout.max_channels > 2)
Mattc7d4b2f2005-06-27 14:59:41 +02004605 spec->surr_switch = 1;
Mattc7d4b2f2005-06-27 14:59:41 +02004606
Charles Chin9009b0e2011-11-03 10:27:27 +01004607 /* find digital out and in converters */
4608 for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) {
4609 unsigned int wid_caps = get_wcaps(codec, i);
4610 if (wid_caps & AC_WCAP_DIGITAL) {
4611 switch (get_wcaps_type(wid_caps)) {
4612 case AC_WID_AUD_OUT:
4613 if (!dig_out)
4614 dig_out = i;
4615 break;
4616 case AC_WID_AUD_IN:
4617 if (!dig_in)
4618 dig_in = i;
4619 break;
4620 }
4621 }
4622 }
Takashi Iwai0852d7a2009-02-11 11:35:15 +01004623 if (spec->autocfg.dig_outs)
Matt Porter3cc08dc2006-01-23 15:27:49 +01004624 spec->multiout.dig_out_nid = dig_out;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02004625 if (dig_in && spec->autocfg.dig_in_pin)
Matt Porter3cc08dc2006-01-23 15:27:49 +01004626 spec->dig_in_nid = dig_in;
Mattc7d4b2f2005-06-27 14:59:41 +02004627
Takashi Iwai603c4012008-07-30 15:01:44 +02004628 if (spec->kctls.list)
4629 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02004630
4631 spec->input_mux = &spec->private_imux;
Matthew Ranostayf8ccbf62008-12-20 17:36:28 -05004632 if (!spec->dinput_mux)
4633 spec->dinput_mux = &spec->private_dimux;
Matthew Ranostayd9737752008-09-07 12:03:41 +02004634 spec->sinput_mux = &spec->private_smux;
Matthew Ranostayb22b4822008-01-22 12:32:30 +01004635 spec->mono_mux = &spec->private_mono_mux;
Mattc7d4b2f2005-06-27 14:59:41 +02004636 return 1;
4637}
4638
Takashi Iwai82bc9552006-03-21 11:24:42 +01004639/* add playback controls for HP output */
4640static int stac9200_auto_create_hp_ctls(struct hda_codec *codec,
4641 struct auto_pin_cfg *cfg)
4642{
4643 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004644 hda_nid_t pin = cfg->hp_pins[0];
Takashi Iwai82bc9552006-03-21 11:24:42 +01004645
4646 if (! pin)
4647 return 0;
4648
Takashi Iwaie35d9d62011-05-17 11:28:16 +02004649 if (is_jack_detectable(codec, pin))
Takashi Iwai82bc9552006-03-21 11:24:42 +01004650 spec->hp_detect = 1;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004651
4652 return 0;
4653}
4654
Richard Fish160ea0d2006-09-06 13:58:25 +02004655/* add playback controls for LFE output */
4656static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
4657 struct auto_pin_cfg *cfg)
4658{
4659 struct sigmatel_spec *spec = codec->spec;
4660 int err;
4661 hda_nid_t lfe_pin = 0x0;
4662 int i;
4663
4664 /*
4665 * search speaker outs and line outs for a mono speaker pin
4666 * with an amp. If one is found, add LFE controls
4667 * for it.
4668 */
4669 for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) {
4670 hda_nid_t pin = spec->autocfg.speaker_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01004671 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02004672 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
4673 if (wcaps == AC_WCAP_OUT_AMP)
4674 /* found a mono speaker with an amp, must be lfe */
4675 lfe_pin = pin;
4676 }
4677
4678 /* if speaker_outs is 0, then speakers may be in line_outs */
4679 if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) {
4680 for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) {
4681 hda_nid_t pin = spec->autocfg.line_out_pins[i];
Takashi Iwai64ed0df2008-02-29 11:57:53 +01004682 unsigned int defcfg;
Takashi Iwai330ee992009-02-20 14:33:36 +01004683 defcfg = snd_hda_codec_get_pincfg(codec, pin);
Harvey Harrison8b551782008-02-29 11:56:48 +01004684 if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) {
Takashi Iwai64ed0df2008-02-29 11:57:53 +01004685 unsigned int wcaps = get_wcaps(codec, pin);
Richard Fish160ea0d2006-09-06 13:58:25 +02004686 wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP);
4687 if (wcaps == AC_WCAP_OUT_AMP)
4688 /* found a mono speaker with an amp,
4689 must be lfe */
4690 lfe_pin = pin;
4691 }
4692 }
4693 }
4694
4695 if (lfe_pin) {
Takashi Iwai7c7767e2009-01-20 15:28:38 +01004696 err = create_controls(codec, "LFE", lfe_pin, 1);
Richard Fish160ea0d2006-09-06 13:58:25 +02004697 if (err < 0)
4698 return err;
4699 }
4700
4701 return 0;
4702}
4703
Mattc7d4b2f2005-06-27 14:59:41 +02004704static int stac9200_parse_auto_config(struct hda_codec *codec)
4705{
4706 struct sigmatel_spec *spec = codec->spec;
4707 int err;
4708
Kailang Yangdf694da2005-12-05 19:42:22 +01004709 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
Mattc7d4b2f2005-06-27 14:59:41 +02004710 return err;
4711
4712 if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
4713 return err;
4714
Takashi Iwai82bc9552006-03-21 11:24:42 +01004715 if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0)
4716 return err;
4717
Richard Fish160ea0d2006-09-06 13:58:25 +02004718 if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0)
4719 return err;
4720
Takashi Iwai355a0ec2008-11-11 16:46:19 +01004721 if (spec->num_muxes > 0) {
4722 err = stac92xx_auto_create_mux_input_ctls(codec);
4723 if (err < 0)
4724 return err;
4725 }
4726
Takashi Iwaie3c75962009-01-23 11:57:22 +01004727 err = stac92xx_add_input_source(spec);
4728 if (err < 0)
4729 return err;
4730
Takashi Iwai0852d7a2009-02-11 11:35:15 +01004731 if (spec->autocfg.dig_outs)
Mattc7d4b2f2005-06-27 14:59:41 +02004732 spec->multiout.dig_out_nid = 0x05;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004733 if (spec->autocfg.dig_in_pin)
Mattc7d4b2f2005-06-27 14:59:41 +02004734 spec->dig_in_nid = 0x04;
Mattc7d4b2f2005-06-27 14:59:41 +02004735
Takashi Iwai603c4012008-07-30 15:01:44 +02004736 if (spec->kctls.list)
4737 spec->mixers[spec->num_mixers++] = spec->kctls.list;
Mattc7d4b2f2005-06-27 14:59:41 +02004738
4739 spec->input_mux = &spec->private_imux;
Matt Porter8b657272006-10-26 17:12:59 +02004740 spec->dinput_mux = &spec->private_dimux;
Mattc7d4b2f2005-06-27 14:59:41 +02004741
4742 return 1;
4743}
4744
Sam Revitch62fe78e2006-05-10 15:09:17 +02004745/*
4746 * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
4747 * funky external mute control using GPIO pins.
4748 */
4749
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01004750static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004751 unsigned int dir_mask, unsigned int data)
Sam Revitch62fe78e2006-05-10 15:09:17 +02004752{
4753 unsigned int gpiostate, gpiomask, gpiodir;
4754
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05004755 snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
4756
Sam Revitch62fe78e2006-05-10 15:09:17 +02004757 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
4758 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004759 gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
Sam Revitch62fe78e2006-05-10 15:09:17 +02004760
4761 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
4762 AC_VERB_GET_GPIO_MASK, 0);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01004763 gpiomask |= mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02004764
4765 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
4766 AC_VERB_GET_GPIO_DIRECTION, 0);
Matthew Ranostay4fe51952008-01-29 15:28:44 +01004767 gpiodir |= dir_mask;
Sam Revitch62fe78e2006-05-10 15:09:17 +02004768
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01004769 /* Configure GPIOx as CMOS */
Sam Revitch62fe78e2006-05-10 15:09:17 +02004770 snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
4771
4772 snd_hda_codec_write(codec, codec->afg, 0,
4773 AC_VERB_SET_GPIO_MASK, gpiomask);
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01004774 snd_hda_codec_read(codec, codec->afg, 0,
4775 AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02004776
4777 msleep(1);
4778
Takashi Iwai76e1ddf2008-01-15 11:39:08 +01004779 snd_hda_codec_read(codec, codec->afg, 0,
4780 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
Sam Revitch62fe78e2006-05-10 15:09:17 +02004781}
4782
Takashi Iwai3a938972011-10-28 01:16:55 +02004783static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004784 unsigned char type, int data)
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004785{
Takashi Iwai3a938972011-10-28 01:16:55 +02004786 struct hda_jack_tbl *event;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004787
Takashi Iwai3a938972011-10-28 01:16:55 +02004788 event = snd_hda_jack_tbl_new(codec, nid);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004789 if (!event)
4790 return -ENOMEM;
Takashi Iwai3a938972011-10-28 01:16:55 +02004791 event->action = type;
4792 event->private_data = data;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004793
Takashi Iwai3a938972011-10-28 01:16:55 +02004794 return 0;
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004795}
4796
David Henningsson29adc4b2012-09-25 11:31:00 +02004797static void handle_unsol_event(struct hda_codec *codec,
4798 struct hda_jack_tbl *event);
4799
Takashi Iwai62558ce2009-07-29 14:23:09 +02004800/* check if given nid is a valid pin and no other events are assigned
4801 * to it. If OK, assign the event, set the unsol flag, and returns 1.
4802 * Otherwise, returns zero.
4803 */
4804static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
4805 unsigned int type)
Takashi Iwai314634b2006-09-21 11:56:18 +02004806{
Takashi Iwai3a938972011-10-28 01:16:55 +02004807 struct hda_jack_tbl *event;
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004808
Takashi Iwaie35d9d62011-05-17 11:28:16 +02004809 if (!is_jack_detectable(codec, nid))
Takashi Iwai62558ce2009-07-29 14:23:09 +02004810 return 0;
Takashi Iwai3a938972011-10-28 01:16:55 +02004811 event = snd_hda_jack_tbl_new(codec, nid);
4812 if (!event)
4813 return -ENOMEM;
4814 if (event->action && event->action != type)
4815 return 0;
4816 event->action = type;
David Henningsson29adc4b2012-09-25 11:31:00 +02004817 event->callback = handle_unsol_event;
Takashi Iwai3a938972011-10-28 01:16:55 +02004818 snd_hda_jack_detect_enable(codec, nid, 0);
Takashi Iwai62558ce2009-07-29 14:23:09 +02004819 return 1;
Takashi Iwai314634b2006-09-21 11:56:18 +02004820}
4821
Takashi Iwaib4ead012012-01-23 18:23:36 +01004822static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004823{
4824 int i;
4825 for (i = 0; i < cfg->hp_outs; i++)
4826 if (cfg->hp_pins[i] == nid)
4827 return 1; /* nid is a HP-Out */
Takashi Iwaib4ead012012-01-23 18:23:36 +01004828 for (i = 0; i < cfg->line_outs; i++)
4829 if (cfg->line_out_pins[i] == nid)
4830 return 1; /* nid is a line-Out */
Matthew Ranostaya64135a2008-01-10 16:55:06 +01004831 return 0; /* nid is not a HP-Out */
4832};
4833
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004834static void stac92xx_power_down(struct hda_codec *codec)
4835{
4836 struct sigmatel_spec *spec = codec->spec;
4837
4838 /* power down inactive DACs */
Takashi Iwai2b635362011-05-02 12:33:43 +02004839 const hda_nid_t *dac;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004840 for (dac = spec->dac_list; *dac; dac++)
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01004841 if (!check_all_dac_nids(spec, *dac))
Takashi Iwai8c2f7672008-12-01 11:54:35 +01004842 snd_hda_codec_write(codec, *dac, 0,
Matthew Ranostayb76c8502008-02-06 14:49:44 +01004843 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
4844}
4845
Takashi Iwaif73d3582008-11-25 08:21:51 +01004846static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
4847 int enable);
4848
Takashi Iwaibc759722013-01-11 17:40:31 +01004849static inline bool get_int_hint(struct hda_codec *codec, const char *key,
4850 int *valp)
Takashi Iwai014c41f2009-12-27 13:53:24 +01004851{
Takashi Iwaibc759722013-01-11 17:40:31 +01004852 return !snd_hda_get_int_hint(codec, key, valp);
Takashi Iwai014c41f2009-12-27 13:53:24 +01004853}
4854
Takashi Iwai6565e4f2009-03-02 14:38:35 +01004855/* override some hints from the hwdep entry */
4856static void stac_store_hints(struct hda_codec *codec)
4857{
4858 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai6565e4f2009-03-02 14:38:35 +01004859 int val;
4860
4861 val = snd_hda_get_bool_hint(codec, "hp_detect");
4862 if (val >= 0)
4863 spec->hp_detect = val;
Takashi Iwai014c41f2009-12-27 13:53:24 +01004864 if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
Takashi Iwai6565e4f2009-03-02 14:38:35 +01004865 spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
4866 spec->gpio_mask;
4867 }
Takashi Iwai014c41f2009-12-27 13:53:24 +01004868 if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
4869 spec->gpio_mask &= spec->gpio_mask;
4870 if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
4871 spec->gpio_dir &= spec->gpio_mask;
4872 if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
4873 spec->eapd_mask &= spec->gpio_mask;
4874 if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
4875 spec->gpio_mute &= spec->gpio_mask;
Takashi Iwai6565e4f2009-03-02 14:38:35 +01004876 val = snd_hda_get_bool_hint(codec, "eapd_switch");
4877 if (val >= 0)
4878 spec->eapd_switch = val;
4879}
4880
Takashi Iwaif2cbba72012-01-11 12:34:11 +01004881static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
4882 const hda_nid_t *pins)
4883{
4884 while (num_pins--)
4885 stac_issue_unsol_event(codec, *pins++);
4886}
4887
4888/* fake event to set up pins */
4889static void stac_fake_hp_events(struct hda_codec *codec)
4890{
4891 struct sigmatel_spec *spec = codec->spec;
4892
4893 if (spec->autocfg.hp_outs)
4894 stac_issue_unsol_events(codec, spec->autocfg.hp_outs,
4895 spec->autocfg.hp_pins);
4896 if (spec->autocfg.line_outs &&
4897 spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0])
4898 stac_issue_unsol_events(codec, spec->autocfg.line_outs,
4899 spec->autocfg.line_out_pins);
4900}
4901
Mattc7d4b2f2005-06-27 14:59:41 +02004902static int stac92xx_init(struct hda_codec *codec)
4903{
4904 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004905 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaif73d3582008-11-25 08:21:51 +01004906 unsigned int gpio;
Takashi Iwaie4973e12008-11-18 09:32:42 +01004907 int i;
Mattc7d4b2f2005-06-27 14:59:41 +02004908
David Henningsson5e68fb32012-08-16 14:11:09 +02004909 if (spec->init)
4910 snd_hda_sequence_write(codec, spec->init);
Mattc7d4b2f2005-06-27 14:59:41 +02004911
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01004912 snd_hda_apply_verbs(codec);
4913
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004914 /* power down adcs initially */
4915 if (spec->powerdown_adcs)
4916 for (i = 0; i < spec->num_adcs; i++)
Takashi Iwai8c2f7672008-12-01 11:54:35 +01004917 snd_hda_codec_write(codec,
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02004918 spec->adc_nids[i], 0,
4919 AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
Takashi Iwaif73d3582008-11-25 08:21:51 +01004920
Takashi Iwai6565e4f2009-03-02 14:38:35 +01004921 /* override some hints */
4922 stac_store_hints(codec);
4923
Takashi Iwaif73d3582008-11-25 08:21:51 +01004924 /* set up GPIO */
4925 gpio = spec->gpio_data;
4926 /* turn on EAPD statically when spec->eapd_switch isn't set.
4927 * otherwise, unsol event will turn it on/off dynamically
4928 */
4929 if (!spec->eapd_switch)
4930 gpio |= spec->eapd_mask;
4931 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio);
4932
Takashi Iwai82bc9552006-03-21 11:24:42 +01004933 /* set up pins */
4934 if (spec->hp_detect) {
Takashi Iwai505cb342006-03-27 12:51:52 +02004935 /* Enable unsolicited responses on the HP widget */
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004936 for (i = 0; i < cfg->hp_outs; i++) {
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004937 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwaic6e4c662008-11-25 11:58:19 +01004938 enable_pin_detect(codec, nid, STAC_HP_EVENT);
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004939 }
Takashi Iwai1c4bdf92009-08-13 08:23:24 +02004940 if (cfg->line_out_type == AUTO_PIN_LINE_OUT &&
4941 cfg->speaker_outs > 0) {
Takashi Iwaifefd67f2009-07-30 18:03:05 +02004942 /* enable pin-detect for line-outs as well */
Takashi Iwai15cfa2b2009-08-03 14:23:33 +02004943 for (i = 0; i < cfg->line_outs; i++) {
4944 hda_nid_t nid = cfg->line_out_pins[i];
Takashi Iwaifefd67f2009-07-30 18:03:05 +02004945 enable_pin_detect(codec, nid, STAC_LO_EVENT);
4946 }
4947 }
4948
Takashi Iwai0a07acaf2007-03-13 10:40:23 +01004949 /* force to enable the first line-out; the others are set up
4950 * in unsol_event
4951 */
4952 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04004953 AC_PINCTL_OUT_EN);
Takashi Iwai82bc9552006-03-21 11:24:42 +01004954 /* fake event to set up pins */
Takashi Iwaif2cbba72012-01-11 12:34:11 +01004955 stac_fake_hp_events(codec);
Takashi Iwai82bc9552006-03-21 11:24:42 +01004956 } else {
4957 stac92xx_auto_init_multi_out(codec);
4958 stac92xx_auto_init_hp_out(codec);
Takashi Iwai12dde4c2008-12-05 13:09:27 +01004959 for (i = 0; i < cfg->hp_outs; i++)
4960 stac_toggle_power_map(codec, cfg->hp_pins[i], 1);
Takashi Iwai82bc9552006-03-21 11:24:42 +01004961 }
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004962 if (spec->auto_mic) {
Takashi Iwai15b4f292009-07-29 16:32:55 +02004963 /* initialize connection to analog input */
Takashi Iwaida2a2aa2009-08-10 07:44:09 +02004964 if (spec->dmux_nids)
4965 snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
Takashi Iwai15b4f292009-07-29 16:32:55 +02004966 AC_VERB_SET_CONNECT_SEL, 0);
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004967 if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
4968 stac_issue_unsol_event(codec, spec->ext_mic.pin);
Charles Chin99077902010-09-17 10:22:32 +02004969 if (enable_pin_detect(codec, spec->dock_mic.pin,
4970 STAC_MIC_EVENT))
4971 stac_issue_unsol_event(codec, spec->dock_mic.pin);
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02004972 }
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004973 for (i = 0; i < cfg->num_inputs; i++) {
4974 hda_nid_t nid = cfg->inputs[i].pin;
4975 int type = cfg->inputs[i].type;
4976 unsigned int pinctl, conf;
Takashi Iwai86e29592010-09-09 14:50:17 +02004977 if (type == AUTO_PIN_MIC) {
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004978 /* for mic pins, force to initialize */
Takashi Iwai47408602012-04-20 13:06:53 +02004979 pinctl = snd_hda_get_default_vref(codec, nid);
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004980 pinctl |= AC_PINCTL_IN_EN;
4981 stac92xx_auto_set_pinctl(codec, nid, pinctl);
4982 } else {
4983 pinctl = snd_hda_codec_read(codec, nid, 0,
4984 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4985 /* if PINCTL already set then skip */
4986 /* Also, if both INPUT and OUTPUT are set,
4987 * it must be a BIOS bug; need to override, too
4988 */
4989 if (!(pinctl & AC_PINCTL_IN_EN) ||
4990 (pinctl & AC_PINCTL_OUT_EN)) {
4991 pinctl &= ~AC_PINCTL_OUT_EN;
Takashi Iwai12dde4c2008-12-05 13:09:27 +01004992 pinctl |= AC_PINCTL_IN_EN;
4993 stac92xx_auto_set_pinctl(codec, nid, pinctl);
Takashi Iwai4f1e6bc2008-11-11 16:47:24 +01004994 }
Takashi Iwaieea7dc92010-08-30 13:06:15 +02004995 }
4996 conf = snd_hda_codec_get_pincfg(codec, nid);
4997 if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
4998 if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
4999 stac_issue_unsol_event(codec, nid);
Takashi Iwaic960a032006-03-23 17:06:28 +01005000 }
Takashi Iwai82bc9552006-03-21 11:24:42 +01005001 }
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005002 for (i = 0; i < spec->num_dmics; i++)
5003 stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
5004 AC_PINCTL_IN_EN);
Takashi Iwai0852d7a2009-02-11 11:35:15 +01005005 if (cfg->dig_out_pins[0])
5006 stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0],
Takashi Iwai82bc9552006-03-21 11:24:42 +01005007 AC_PINCTL_OUT_EN);
5008 if (cfg->dig_in_pin)
5009 stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
5010 AC_PINCTL_IN_EN);
Takashi Iwaif73d3582008-11-25 08:21:51 +01005011 for (i = 0; i < spec->num_pwrs; i++) {
5012 hda_nid_t nid = spec->pwr_nids[i];
Takashi Iwai6e1c39c2012-06-26 17:35:10 +02005013 unsigned int pinctl, def_conf;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005014
Takashi Iwaibfc89de2012-05-15 09:02:26 +02005015 def_conf = snd_hda_codec_get_pincfg(codec, nid);
5016 def_conf = get_defcfg_connect(def_conf);
5017 if (def_conf == AC_JACK_PORT_NONE) {
5018 /* power off unused ports */
5019 stac_toggle_power_map(codec, nid, 0);
5020 continue;
5021 }
Takashi Iwai6e1c39c2012-06-26 17:35:10 +02005022 if (def_conf == AC_JACK_PORT_FIXED) {
5023 /* no need for jack detection for fixed pins */
5024 stac_toggle_power_map(codec, nid, 1);
5025 continue;
5026 }
Takashi Iwaieb632122008-12-19 16:39:48 +01005027 /* power on when no jack detection is available */
Takashi Iwai542c9a02011-11-29 13:01:30 +01005028 /* or when the VREF is used for controlling LED */
5029 if (!spec->hp_detect ||
Takashi Iwaibfc89de2012-05-15 09:02:26 +02005030 spec->vref_mute_led_nid == nid ||
5031 !is_jack_detectable(codec, nid)) {
Takashi Iwaieb632122008-12-19 16:39:48 +01005032 stac_toggle_power_map(codec, nid, 1);
5033 continue;
5034 }
5035
Takashi Iwaib4ead012012-01-23 18:23:36 +01005036 if (is_nid_out_jack_pin(cfg, nid))
Takashi Iwaif73d3582008-11-25 08:21:51 +01005037 continue; /* already has an unsol event */
Sam Revitch62fe78e2006-05-10 15:09:17 +02005038
Takashi Iwaif73d3582008-11-25 08:21:51 +01005039 pinctl = snd_hda_codec_read(codec, nid, 0,
5040 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
5041 /* outputs are only ports capable of power management
5042 * any attempts on powering down a input port cause the
5043 * referenced VREF to act quirky.
5044 */
Takashi Iwaieb632122008-12-19 16:39:48 +01005045 if (pinctl & AC_PINCTL_IN_EN) {
5046 stac_toggle_power_map(codec, nid, 1);
Takashi Iwaif73d3582008-11-25 08:21:51 +01005047 continue;
Takashi Iwaieb632122008-12-19 16:39:48 +01005048 }
Charles Chinafef2cf2011-11-11 08:05:28 +01005049 if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
Takashi Iwai62558ce2009-07-29 14:23:09 +02005050 stac_issue_unsol_event(codec, nid);
Charles Chinafef2cf2011-11-11 08:05:28 +01005051 continue;
5052 }
5053 /* none of the above, turn the port OFF */
5054 stac_toggle_power_map(codec, nid, 0);
Takashi Iwaif73d3582008-11-25 08:21:51 +01005055 }
Takashi Iwaic21bd022010-02-08 15:16:08 +01005056
Takashi Iwaic21bd022010-02-08 15:16:08 +01005057 /* sync mute LED */
Takashi Iwai1f43f6c2012-07-31 10:40:05 +02005058 if (spec->gpio_led) {
5059 if (spec->vmaster_mute.hook)
5060 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
5061 else /* the very first init call doesn't have vmaster yet */
5062 stac92xx_update_led_status(codec, false);
5063 }
Takashi Iwaic8822462012-05-15 09:11:36 +02005064
5065 /* sync the power-map */
5066 if (spec->num_pwrs)
5067 snd_hda_codec_write(codec, codec->afg, 0,
5068 AC_VERB_IDT_SET_POWER_MAP,
5069 spec->power_map_bits);
Takashi Iwaif73d3582008-11-25 08:21:51 +01005070 if (spec->dac_list)
5071 stac92xx_power_down(codec);
Mattc7d4b2f2005-06-27 14:59:41 +02005072 return 0;
5073}
5074
Takashi Iwai603c4012008-07-30 15:01:44 +02005075static void stac92xx_free_kctls(struct hda_codec *codec)
5076{
5077 struct sigmatel_spec *spec = codec->spec;
5078
5079 if (spec->kctls.list) {
5080 struct snd_kcontrol_new *kctl = spec->kctls.list;
5081 int i;
5082 for (i = 0; i < spec->kctls.used; i++)
5083 kfree(kctl[i].name);
5084 }
5085 snd_array_free(&spec->kctls);
5086}
5087
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005088static void stac92xx_shutup_pins(struct hda_codec *codec)
5089{
5090 unsigned int i, def_conf;
5091
5092 if (codec->bus->shutdown)
5093 return;
5094 for (i = 0; i < codec->init_pins.used; i++) {
5095 struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
5096 def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
5097 if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02005098 snd_hda_set_pin_ctl(codec, pin->nid, 0);
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005099 }
5100}
5101
Takashi Iwai167eae52009-11-06 15:47:50 +01005102static void stac92xx_shutup(struct hda_codec *codec)
5103{
5104 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai167eae52009-11-06 15:47:50 +01005105
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005106 stac92xx_shutup_pins(codec);
Takashi Iwai167eae52009-11-06 15:47:50 +01005107
5108 if (spec->eapd_mask)
5109 stac_gpio_set(codec, spec->gpio_mask,
5110 spec->gpio_dir, spec->gpio_data &
5111 ~spec->eapd_mask);
5112}
5113
Matt2f2f4252005-04-13 14:45:30 +02005114static void stac92xx_free(struct hda_codec *codec)
5115{
Mattc7d4b2f2005-06-27 14:59:41 +02005116 struct sigmatel_spec *spec = codec->spec;
Mattc7d4b2f2005-06-27 14:59:41 +02005117
5118 if (! spec)
5119 return;
5120
Mattc7d4b2f2005-06-27 14:59:41 +02005121 kfree(spec);
Matthew Ranostay1cd22242008-07-18 18:20:52 +02005122 snd_hda_detach_beep_device(codec);
Matt2f2f4252005-04-13 14:45:30 +02005123}
5124
Matt4e550962005-07-04 17:51:39 +02005125static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
5126 unsigned int flag)
5127{
Takashi Iwai8ce84192009-01-22 16:59:20 +01005128 unsigned int old_ctl, pin_ctl;
5129
5130 pin_ctl = snd_hda_codec_read(codec, nid,
Matt4e550962005-07-04 17:51:39 +02005131 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Steve Longerbeam7b043892007-05-03 20:50:03 +02005132
Takashi Iwaif9acba42007-05-29 18:01:06 +02005133 if (pin_ctl & AC_PINCTL_IN_EN) {
5134 /*
5135 * we need to check the current set-up direction of
5136 * shared input pins since they can be switched via
5137 * "xxx as Output" mixer switch
5138 */
5139 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005140 if (nid == spec->line_switch || nid == spec->mic_switch)
Takashi Iwaif9acba42007-05-29 18:01:06 +02005141 return;
5142 }
5143
Takashi Iwai8ce84192009-01-22 16:59:20 +01005144 old_ctl = pin_ctl;
Steve Longerbeam7b043892007-05-03 20:50:03 +02005145 /* if setting pin direction bits, clear the current
5146 direction bits first */
5147 if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))
5148 pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
5149
Takashi Iwai8ce84192009-01-22 16:59:20 +01005150 pin_ctl |= flag;
5151 if (old_ctl != pin_ctl)
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02005152 snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl);
Matt4e550962005-07-04 17:51:39 +02005153}
5154
5155static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
5156 unsigned int flag)
5157{
5158 unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
5159 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
Takashi Iwai8ce84192009-01-22 16:59:20 +01005160 if (pin_ctl & flag)
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02005161 snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag);
Matt4e550962005-07-04 17:51:39 +02005162}
5163
Takashi Iwaid56757a2009-11-18 08:00:14 +01005164static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai314634b2006-09-21 11:56:18 +02005165{
5166 if (!nid)
5167 return 0;
Takashi Iwaia252c812009-12-25 22:56:20 +01005168 return snd_hda_jack_detect(codec, nid);
Takashi Iwai314634b2006-09-21 11:56:18 +02005169}
5170
Takashi Iwaifefd67f2009-07-30 18:03:05 +02005171static void stac92xx_line_out_detect(struct hda_codec *codec,
5172 int presence)
5173{
5174 struct sigmatel_spec *spec = codec->spec;
5175 struct auto_pin_cfg *cfg = &spec->autocfg;
5176 int i;
5177
David Henningsson042b92c2012-08-22 16:10:43 +02005178 if (cfg->speaker_outs == 0)
5179 return;
5180
Takashi Iwaifefd67f2009-07-30 18:03:05 +02005181 for (i = 0; i < cfg->line_outs; i++) {
5182 if (presence)
5183 break;
5184 presence = get_pin_presence(codec, cfg->line_out_pins[i]);
5185 if (presence) {
5186 unsigned int pinctl;
5187 pinctl = snd_hda_codec_read(codec,
5188 cfg->line_out_pins[i], 0,
5189 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
5190 if (pinctl & AC_PINCTL_IN_EN)
5191 presence = 0; /* mic- or line-input */
5192 }
5193 }
5194
5195 if (presence) {
5196 /* disable speakers */
5197 for (i = 0; i < cfg->speaker_outs; i++)
5198 stac92xx_reset_pinctl(codec, cfg->speaker_pins[i],
5199 AC_PINCTL_OUT_EN);
5200 if (spec->eapd_mask && spec->eapd_switch)
5201 stac_gpio_set(codec, spec->gpio_mask,
5202 spec->gpio_dir, spec->gpio_data &
5203 ~spec->eapd_mask);
5204 } else {
5205 /* enable speakers */
5206 for (i = 0; i < cfg->speaker_outs; i++)
5207 stac92xx_set_pinctl(codec, cfg->speaker_pins[i],
5208 AC_PINCTL_OUT_EN);
5209 if (spec->eapd_mask && spec->eapd_switch)
5210 stac_gpio_set(codec, spec->gpio_mask,
5211 spec->gpio_dir, spec->gpio_data |
5212 spec->eapd_mask);
5213 }
5214}
5215
Takashi Iwaid7a89432008-11-12 09:48:04 +01005216/* return non-zero if the hp-pin of the given array index isn't
5217 * a jack-detection target
5218 */
5219static int no_hp_sensing(struct sigmatel_spec *spec, int i)
5220{
5221 struct auto_pin_cfg *cfg = &spec->autocfg;
5222
5223 /* ignore sensing of shared line and mic jacks */
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005224 if (cfg->hp_pins[i] == spec->line_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01005225 return 1;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005226 if (cfg->hp_pins[i] == spec->mic_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01005227 return 1;
5228 /* ignore if the pin is set as line-out */
5229 if (cfg->hp_pins[i] == spec->hp_switch)
5230 return 1;
5231 return 0;
5232}
5233
Takashi Iwaic6e4c662008-11-25 11:58:19 +01005234static void stac92xx_hp_detect(struct hda_codec *codec)
Matt4e550962005-07-04 17:51:39 +02005235{
5236 struct sigmatel_spec *spec = codec->spec;
5237 struct auto_pin_cfg *cfg = &spec->autocfg;
5238 int i, presence;
5239
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005240 presence = 0;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01005241 if (spec->gpio_mute)
5242 presence = !(snd_hda_codec_read(codec, codec->afg, 0,
5243 AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
5244
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005245 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai314634b2006-09-21 11:56:18 +02005246 if (presence)
5247 break;
Takashi Iwaid7a89432008-11-12 09:48:04 +01005248 if (no_hp_sensing(spec, i))
5249 continue;
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01005250 presence = get_pin_presence(codec, cfg->hp_pins[i]);
5251 if (presence) {
5252 unsigned int pinctl;
5253 pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0,
5254 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
5255 if (pinctl & AC_PINCTL_IN_EN)
5256 presence = 0; /* mic- or line-input */
5257 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005258 }
Matt4e550962005-07-04 17:51:39 +02005259
5260 if (presence) {
Takashi Iwaid7a89432008-11-12 09:48:04 +01005261 /* disable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02005262 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01005263 stac92xx_reset_pinctl(codec, spec->hp_switch,
5264 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02005265 for (i = 0; i < cfg->line_outs; i++)
5266 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
5267 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02005268 } else {
Takashi Iwaid7a89432008-11-12 09:48:04 +01005269 /* enable lineouts */
Matthew Ranostay7c2ba972008-04-16 13:13:59 +02005270 if (spec->hp_switch)
Takashi Iwaid7a89432008-11-12 09:48:04 +01005271 stac92xx_set_pinctl(codec, spec->hp_switch,
5272 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02005273 for (i = 0; i < cfg->line_outs; i++)
5274 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
5275 AC_PINCTL_OUT_EN);
Matt4e550962005-07-04 17:51:39 +02005276 }
Takashi Iwaifefd67f2009-07-30 18:03:05 +02005277 stac92xx_line_out_detect(codec, presence);
Takashi Iwaid7a89432008-11-12 09:48:04 +01005278 /* toggle hp outs */
5279 for (i = 0; i < cfg->hp_outs; i++) {
5280 unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
5281 if (no_hp_sensing(spec, i))
5282 continue;
Takashi Iwai7bff1722012-02-29 09:41:17 +01005283 if (1 /*presence*/)
Takashi Iwaid7a89432008-11-12 09:48:04 +01005284 stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
Takashi Iwai8317e0b2009-01-14 07:56:51 +01005285#if 0 /* FIXME */
5286/* Resetting the pinctl like below may lead to (a sort of) regressions
5287 * on some devices since they use the HP pin actually for line/speaker
5288 * outs although the default pin config shows a different pin (that is
5289 * wrong and useless).
5290 *
5291 * So, it's basically a problem of default pin configs, likely a BIOS issue.
5292 * But, disabling the code below just works around it, and I'm too tired of
5293 * bug reports with such devices...
5294 */
Takashi Iwaid7a89432008-11-12 09:48:04 +01005295 else
5296 stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
Takashi Iwai8317e0b2009-01-14 07:56:51 +01005297#endif /* FIXME */
Takashi Iwaid7a89432008-11-12 09:48:04 +01005298 }
Matt4e550962005-07-04 17:51:39 +02005299}
5300
Takashi Iwaif73d3582008-11-25 08:21:51 +01005301static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
5302 int enable)
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005303{
5304 struct sigmatel_spec *spec = codec->spec;
Takashi Iwaif73d3582008-11-25 08:21:51 +01005305 unsigned int idx, val;
5306
5307 for (idx = 0; idx < spec->num_pwrs; idx++) {
5308 if (spec->pwr_nids[idx] == nid)
5309 break;
5310 }
5311 if (idx >= spec->num_pwrs)
5312 return;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02005313
Charles Chinafef2cf2011-11-11 08:05:28 +01005314 idx = 1 << idx;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005315
Takashi Iwaic8822462012-05-15 09:11:36 +02005316 val = spec->power_map_bits;
Takashi Iwaif73d3582008-11-25 08:21:51 +01005317 if (enable)
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005318 val &= ~idx;
5319 else
5320 val |= idx;
5321
5322 /* power down unused output ports */
Takashi Iwaic8822462012-05-15 09:11:36 +02005323 if (val != spec->power_map_bits) {
5324 spec->power_map_bits = val;
5325 snd_hda_codec_write(codec, codec->afg, 0,
5326 AC_VERB_IDT_SET_POWER_MAP, val);
5327 }
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04005328}
5329
Takashi Iwaif73d3582008-11-25 08:21:51 +01005330static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
5331{
Takashi Iwaie6e3ea22008-12-05 12:54:56 +01005332 stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
Takashi Iwaif73d3582008-11-25 08:21:51 +01005333}
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005334
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02005335/* get the pin connection (fixed, none, etc) */
5336static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
5337{
5338 struct sigmatel_spec *spec = codec->spec;
5339 unsigned int cfg;
5340
5341 cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
5342 return get_defcfg_connect(cfg);
5343}
5344
5345static int stac92xx_connected_ports(struct hda_codec *codec,
Takashi Iwai2b635362011-05-02 12:33:43 +02005346 const hda_nid_t *nids, int num_nids)
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02005347{
5348 struct sigmatel_spec *spec = codec->spec;
5349 int idx, num;
5350 unsigned int def_conf;
5351
5352 for (num = 0; num < num_nids; num++) {
5353 for (idx = 0; idx < spec->num_pins; idx++)
5354 if (spec->pin_nids[idx] == nids[num])
5355 break;
5356 if (idx >= spec->num_pins)
5357 break;
5358 def_conf = stac_get_defcfg_connect(codec, idx);
5359 if (def_conf == AC_JACK_PORT_NONE)
5360 break;
5361 }
5362 return num;
5363}
5364
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005365static void stac92xx_mic_detect(struct hda_codec *codec)
5366{
5367 struct sigmatel_spec *spec = codec->spec;
5368 struct sigmatel_mic_route *mic;
5369
5370 if (get_pin_presence(codec, spec->ext_mic.pin))
5371 mic = &spec->ext_mic;
Charles Chin99077902010-09-17 10:22:32 +02005372 else if (get_pin_presence(codec, spec->dock_mic.pin))
5373 mic = &spec->dock_mic;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005374 else
5375 mic = &spec->int_mic;
Takashi Iwai02d33322009-10-01 16:38:11 +02005376 if (mic->dmux_idx >= 0)
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005377 snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0,
5378 AC_VERB_SET_CONNECT_SEL,
5379 mic->dmux_idx);
Takashi Iwai02d33322009-10-01 16:38:11 +02005380 if (mic->mux_idx >= 0)
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005381 snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0,
5382 AC_VERB_SET_CONNECT_SEL,
5383 mic->mux_idx);
5384}
5385
Takashi Iwai1835a0f2011-10-27 22:12:46 +02005386static void handle_unsol_event(struct hda_codec *codec,
Takashi Iwai3a938972011-10-28 01:16:55 +02005387 struct hda_jack_tbl *event)
Takashi Iwai314634b2006-09-21 11:56:18 +02005388{
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005389 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai1835a0f2011-10-27 22:12:46 +02005390 int data;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005391
Takashi Iwai3a938972011-10-28 01:16:55 +02005392 switch (event->action) {
Takashi Iwai314634b2006-09-21 11:56:18 +02005393 case STAC_HP_EVENT:
Takashi Iwaifefd67f2009-07-30 18:03:05 +02005394 case STAC_LO_EVENT:
Takashi Iwai16ffe322009-08-04 13:40:54 +02005395 stac92xx_hp_detect(codec);
Takashi Iwaifefd67f2009-07-30 18:03:05 +02005396 break;
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005397 case STAC_MIC_EVENT:
5398 stac92xx_mic_detect(codec);
5399 break;
5400 }
5401
Takashi Iwai3a938972011-10-28 01:16:55 +02005402 switch (event->action) {
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005403 case STAC_HP_EVENT:
Takashi Iwaifefd67f2009-07-30 18:03:05 +02005404 case STAC_LO_EVENT:
Takashi Iwai3d21d3f2009-07-29 14:32:56 +02005405 case STAC_MIC_EVENT:
Matthew Ranostay74aeaab2008-10-25 01:06:04 -04005406 case STAC_INSERT_EVENT:
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005407 case STAC_PWR_EVENT:
Takashi Iwaic6e4c662008-11-25 11:58:19 +01005408 if (spec->num_pwrs > 0)
5409 stac92xx_pin_sense(codec, event->nid);
Matthew Ranostayfd60cc82009-04-06 09:30:46 -04005410
5411 switch (codec->subsystem_id) {
5412 case 0x103c308f:
5413 if (event->nid == 0xb) {
5414 int pin = AC_PINCTL_IN_EN;
5415
5416 if (get_pin_presence(codec, 0xa)
5417 && get_pin_presence(codec, 0xb))
5418 pin |= AC_PINCTL_VREF_80;
5419 if (!get_pin_presence(codec, 0xb))
5420 pin |= AC_PINCTL_VREF_80;
5421
5422 /* toggle VREF state based on mic + hp pin
5423 * status
5424 */
5425 stac92xx_auto_set_pinctl(codec, 0x0a, pin);
5426 }
5427 }
Matthew Ranostay72474be2008-10-09 09:32:17 -04005428 break;
Takashi Iwaic6e4c662008-11-25 11:58:19 +01005429 case STAC_VREF_EVENT:
5430 data = snd_hda_codec_read(codec, codec->afg, 0,
5431 AC_VERB_GET_GPIO_DATA, 0);
Matthew Ranostay72474be2008-10-09 09:32:17 -04005432 /* toggle VREF state based on GPIOx status */
5433 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
Takashi Iwai3a938972011-10-28 01:16:55 +02005434 !!(data & (1 << event->private_data)));
Matthew Ranostay72474be2008-10-09 09:32:17 -04005435 break;
Takashi Iwai314634b2006-09-21 11:56:18 +02005436 }
5437}
5438
Takashi Iwai1835a0f2011-10-27 22:12:46 +02005439static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
5440{
Takashi Iwai3a938972011-10-28 01:16:55 +02005441 struct hda_jack_tbl *event = snd_hda_jack_tbl_get(codec, nid);
Takashi Iwai1835a0f2011-10-27 22:12:46 +02005442 if (!event)
5443 return;
5444 handle_unsol_event(codec, event);
5445}
5446
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305447static int hp_blike_system(u32 subsystem_id);
5448
5449static void set_hp_led_gpio(struct hda_codec *codec)
5450{
5451 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai07f80442010-02-08 15:06:13 +01005452 unsigned int gpio;
5453
Takashi Iwai26ebe0a2010-05-11 08:36:29 +02005454 if (spec->gpio_led)
5455 return;
5456
Takashi Iwai07f80442010-02-08 15:06:13 +01005457 gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
5458 gpio &= AC_GPIO_IO_COUNT;
5459 if (gpio > 3)
5460 spec->gpio_led = 0x08; /* GPIO 3 */
5461 else
5462 spec->gpio_led = 0x01; /* GPIO 0 */
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305463}
5464
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005465/*
5466 * This method searches for the mute LED GPIO configuration
5467 * provided as OEM string in SMBIOS. The format of that string
5468 * is HP_Mute_LED_P_G or HP_Mute_LED_P
5469 * where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
5470 * that corresponds to the NOT muted state of the master volume
5471 * and G is the index of the GPIO to use as the mute LED control (0..9)
5472 * If _G portion is missing it is assigned based on the codec ID
5473 *
5474 * So, HP B-series like systems may have HP_Mute_LED_0 (current models)
5475 * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305476 *
5477 *
5478 * The dv-series laptops don't seem to have the HP_Mute_LED* strings in
5479 * SMBIOS - at least the ones I have seen do not have them - which include
5480 * my own system (HP Pavilion dv6-1110ax) and my cousin's
5481 * HP Pavilion dv9500t CTO.
5482 * Need more information on whether it is true across the entire series.
5483 * -- kunal
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005484 */
Vitaliy Kulikov6a557c92011-12-12 17:35:13 -06005485static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005486{
5487 struct sigmatel_spec *spec = codec->spec;
5488 const struct dmi_device *dev = NULL;
5489
Takashi Iwai75609312012-05-14 16:52:00 +02005490 if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
5491 get_int_hint(codec, "gpio_led_polarity",
5492 &spec->gpio_led_polarity);
5493 return 1;
5494 }
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005495 if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
5496 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
5497 NULL, dev))) {
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005498 if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305499 &spec->gpio_led_polarity,
5500 &spec->gpio_led) == 2) {
Takashi Iwaif1a73742011-12-04 13:44:06 +01005501 unsigned int max_gpio;
5502 max_gpio = snd_hda_param_read(codec, codec->afg,
5503 AC_PAR_GPIO_CAP);
5504 max_gpio &= AC_GPIO_IO_COUNT;
5505 if (spec->gpio_led < max_gpio)
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005506 spec->gpio_led = 1 << spec->gpio_led;
Takashi Iwaif1a73742011-12-04 13:44:06 +01005507 else
5508 spec->vref_mute_led_nid = spec->gpio_led;
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005509 return 1;
5510 }
5511 if (sscanf(dev->name, "HP_Mute_LED_%d",
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305512 &spec->gpio_led_polarity) == 1) {
5513 set_hp_led_gpio(codec);
5514 return 1;
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005515 }
Gustavo Maciel Dias Vieirae2ef36c2011-12-13 11:47:22 -02005516 /* BIOS bug: unfilled OEM string */
5517 if (strstr(dev->name, "HP_Mute_LED_P_G")) {
5518 set_hp_led_gpio(codec);
Gustavo Maciel Dias Vieiraa6a600d2012-01-24 13:27:56 -02005519 switch (codec->subsystem_id) {
5520 case 0x103c148a:
5521 spec->gpio_led_polarity = 0;
5522 break;
5523 default:
5524 spec->gpio_led_polarity = 1;
5525 break;
5526 }
Gustavo Maciel Dias Vieirae2ef36c2011-12-13 11:47:22 -02005527 return 1;
5528 }
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005529 }
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305530
5531 /*
5532 * Fallback case - if we don't find the DMI strings,
Vitaliy Kulikov6a557c92011-12-12 17:35:13 -06005533 * we statically set the GPIO - if not a B-series system
5534 * and default polarity is provided
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305535 */
Vitaliy Kulikov6a557c92011-12-12 17:35:13 -06005536 if (!hp_blike_system(codec->subsystem_id) &&
5537 (default_polarity == 0 || default_polarity == 1)) {
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305538 set_hp_led_gpio(codec);
Takashi Iwaidce17d42010-02-09 09:25:26 +01005539 spec->gpio_led_polarity = default_polarity;
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05305540 return 1;
5541 }
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005542 }
5543 return 0;
5544}
5545
5546static int hp_blike_system(u32 subsystem_id)
Randy Dunlap78987bd2009-11-05 09:22:30 -08005547{
5548 switch (subsystem_id) {
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005549 case 0x103c1520:
5550 case 0x103c1521:
5551 case 0x103c1523:
5552 case 0x103c1524:
5553 case 0x103c1525:
Randy Dunlap78987bd2009-11-05 09:22:30 -08005554 case 0x103c1722:
5555 case 0x103c1723:
5556 case 0x103c1724:
5557 case 0x103c1725:
5558 case 0x103c1726:
5559 case 0x103c1727:
5560 case 0x103c1728:
5561 case 0x103c1729:
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01005562 case 0x103c172a:
5563 case 0x103c172b:
5564 case 0x103c307e:
5565 case 0x103c307f:
5566 case 0x103c3080:
5567 case 0x103c3081:
5568 case 0x103c7007:
5569 case 0x103c7008:
Randy Dunlap78987bd2009-11-05 09:22:30 -08005570 return 1;
5571 }
5572 return 0;
5573}
5574
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01005575#ifdef CONFIG_PROC_FS
5576static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
5577 struct hda_codec *codec, hda_nid_t nid)
5578{
5579 if (nid == codec->afg)
5580 snd_iprintf(buffer, "Power-Map: 0x%02x\n",
Takashi Iwaic8822462012-05-15 09:11:36 +02005581 snd_hda_codec_read(codec, nid, 0,
5582 AC_VERB_IDT_GET_POWER_MAP, 0));
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01005583}
5584
5585static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
5586 struct hda_codec *codec,
5587 unsigned int verb)
5588{
5589 snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
5590 snd_hda_codec_read(codec, codec->afg, 0, verb, 0));
5591}
5592
5593/* stac92hd71bxx, stac92hd73xx */
5594static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
5595 struct hda_codec *codec, hda_nid_t nid)
5596{
5597 stac92hd_proc_hook(buffer, codec, nid);
5598 if (nid == codec->afg)
5599 analog_loop_proc_hook(buffer, codec, 0xfa0);
5600}
5601
5602static void stac9205_proc_hook(struct snd_info_buffer *buffer,
5603 struct hda_codec *codec, hda_nid_t nid)
5604{
5605 if (nid == codec->afg)
5606 analog_loop_proc_hook(buffer, codec, 0xfe0);
5607}
5608
5609static void stac927x_proc_hook(struct snd_info_buffer *buffer,
5610 struct hda_codec *codec, hda_nid_t nid)
5611{
5612 if (nid == codec->afg)
5613 analog_loop_proc_hook(buffer, codec, 0xfeb);
5614}
5615#else
5616#define stac92hd_proc_hook NULL
5617#define stac92hd7x_proc_hook NULL
5618#define stac9205_proc_hook NULL
5619#define stac927x_proc_hook NULL
5620#endif
5621
Takashi Iwai2a439522011-07-26 09:52:50 +02005622#ifdef CONFIG_PM
Mattff6fdc32005-06-27 15:06:52 +02005623static int stac92xx_resume(struct hda_codec *codec)
5624{
Takashi Iwai2c885872008-11-18 09:36:55 +01005625 stac92xx_init(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005626 snd_hda_codec_resume_amp(codec);
5627 snd_hda_codec_resume_cache(codec);
Takashi Iwai2c885872008-11-18 09:36:55 +01005628 /* fake event to set up pins again to override cached values */
Takashi Iwaif2cbba72012-01-11 12:34:11 +01005629 stac_fake_hp_events(codec);
Mattff6fdc32005-06-27 15:06:52 +02005630 return 0;
5631}
Matthew Ranostayc6798d22008-11-18 20:54:17 -05005632
Takashi Iwai68cb2b52012-07-02 15:20:37 +02005633static int stac92xx_suspend(struct hda_codec *codec)
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005634{
5635 stac92xx_shutup(codec);
5636 return 0;
5637}
5638
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005639static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
5640 unsigned int power_state)
5641{
5642 unsigned int afg_power_state = power_state;
5643 struct sigmatel_spec *spec = codec->spec;
5644
5645 if (power_state == AC_PWRST_D3) {
Takashi Iwaif1a73742011-12-04 13:44:06 +01005646 if (spec->vref_mute_led_nid) {
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005647 /* with vref-out pin used for mute led control
5648 * codec AFG is prevented from D3 state
5649 */
5650 afg_power_state = AC_PWRST_D1;
5651 }
5652 /* this delay seems necessary to avoid click noise at power-down */
5653 msleep(100);
5654 }
5655 snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
5656 afg_power_state);
5657 snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
5658}
Takashi Iwai350eba432012-03-16 16:09:03 +01005659#else
5660#define stac92xx_suspend NULL
5661#define stac92xx_resume NULL
Takashi Iwai350eba432012-03-16 16:09:03 +01005662#define stac92xx_set_power_state NULL
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01005663#endif /* CONFIG_PM */
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005664
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01005665/* update mute-LED accoring to the master switch */
5666static void stac92xx_update_led_status(struct hda_codec *codec, int enabled)
Christoph Plattnerae6241f2009-03-08 23:19:05 +01005667{
5668 struct sigmatel_spec *spec = codec->spec;
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01005669 int muted = !enabled;
Takashi Iwai6fce61a2009-03-10 07:48:57 +01005670
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005671 if (!spec->gpio_led)
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01005672 return;
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005673
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01005674 /* LED state is inverted on these systems */
5675 if (spec->gpio_led_polarity)
5676 muted = !muted;
5677
Takashi Iwaif1a73742011-12-04 13:44:06 +01005678 if (!spec->vref_mute_led_nid) {
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005679 if (muted)
Takashi Iwai3e843192012-04-19 12:04:03 +02005680 spec->gpio_data |= spec->gpio_led;
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005681 else
Takashi Iwai3e843192012-04-19 12:04:03 +02005682 spec->gpio_data &= ~spec->gpio_led;
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05005683 stac_gpio_set(codec, spec->gpio_mask,
5684 spec->gpio_dir, spec->gpio_data);
5685 } else {
Takashi Iwai2faa3bf2012-03-12 12:30:22 +01005686 spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
Takashi Iwaif1a73742011-12-04 13:44:06 +01005687 stac_vrefout_set(codec, spec->vref_mute_led_nid,
5688 spec->vref_led);
Christoph Plattnerae6241f2009-03-08 23:19:05 +01005689 }
Takashi Iwaib4e81872009-11-18 17:20:24 +01005690}
Vitaliy Kulikov7df1ce12011-07-25 17:52:57 -05005691
Takashi Iwai2b635362011-05-02 12:33:43 +02005692static const struct hda_codec_ops stac92xx_patch_ops = {
Matt2f2f4252005-04-13 14:45:30 +02005693 .build_controls = stac92xx_build_controls,
5694 .build_pcms = stac92xx_build_pcms,
5695 .init = stac92xx_init,
5696 .free = stac92xx_free,
David Henningsson29adc4b2012-09-25 11:31:00 +02005697 .unsol_event = snd_hda_jack_unsol_event,
Takashi Iwai2a439522011-07-26 09:52:50 +02005698#ifdef CONFIG_PM
Matthew Ranostayc6798d22008-11-18 20:54:17 -05005699 .suspend = stac92xx_suspend,
Mattff6fdc32005-06-27 15:06:52 +02005700 .resume = stac92xx_resume,
5701#endif
Takashi Iwaifb8d1a32009-11-10 16:02:29 +01005702 .reboot_notify = stac92xx_shutup,
Matt2f2f4252005-04-13 14:45:30 +02005703};
5704
Takashi Iwai361dab32012-05-09 14:35:27 +02005705static int alloc_stac_spec(struct hda_codec *codec, int num_pins,
5706 const hda_nid_t *pin_nids)
5707{
5708 struct sigmatel_spec *spec;
5709
5710 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5711 if (!spec)
5712 return -ENOMEM;
5713 codec->spec = spec;
5714 codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
5715 spec->num_pins = num_pins;
5716 spec->pin_nids = pin_nids;
5717 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
5718 return 0;
5719}
5720
Matt2f2f4252005-04-13 14:45:30 +02005721static int patch_stac9200(struct hda_codec *codec)
5722{
5723 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02005724 int err;
Matt2f2f4252005-04-13 14:45:30 +02005725
Takashi Iwai361dab32012-05-09 14:35:27 +02005726 err = alloc_stac_spec(codec, ARRAY_SIZE(stac9200_pin_nids),
5727 stac9200_pin_nids);
5728 if (err < 0)
5729 return err;
Matt2f2f4252005-04-13 14:45:30 +02005730
Takashi Iwai361dab32012-05-09 14:35:27 +02005731 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01005732 spec->linear_tone_beep = 1;
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01005733
5734 snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl,
5735 stac9200_fixups);
Matt2f2f4252005-04-13 14:45:30 +02005736
5737 spec->multiout.max_channels = 2;
5738 spec->multiout.num_dacs = 1;
5739 spec->multiout.dac_nids = stac9200_dac_nids;
5740 spec->adc_nids = stac9200_adc_nids;
5741 spec->mux_nids = stac9200_mux_nids;
Mattdabbed62005-06-14 10:19:34 +02005742 spec->num_muxes = 1;
Matt Porter8b657272006-10-26 17:12:59 +02005743 spec->num_dmics = 0;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005744 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005745 spec->num_pwrs = 0;
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01005746 snd_hda_add_verbs(codec, stac9200_eapd_init);
Mattc7d4b2f2005-06-27 14:59:41 +02005747
Matt2f2f4252005-04-13 14:45:30 +02005748 spec->mixer = stac9200_mixer;
Mattc7d4b2f2005-06-27 14:59:41 +02005749
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01005750 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
Takashi Iwai117f2572008-03-18 09:53:23 +01005751
Mattc7d4b2f2005-06-27 14:59:41 +02005752 err = stac9200_parse_auto_config(codec);
5753 if (err < 0) {
5754 stac92xx_free(codec);
5755 return err;
5756 }
Matt2f2f4252005-04-13 14:45:30 +02005757
5758 codec->patch_ops = stac92xx_patch_ops;
5759
Takashi Iwaid39a3ae2013-01-14 14:06:26 +01005760 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
5761
Matt2f2f4252005-04-13 14:45:30 +02005762 return 0;
5763}
5764
Tobin Davis8e21c342007-01-08 11:04:17 +01005765static int patch_stac925x(struct hda_codec *codec)
5766{
5767 struct sigmatel_spec *spec;
5768 int err;
5769
Takashi Iwai361dab32012-05-09 14:35:27 +02005770 err = alloc_stac_spec(codec, ARRAY_SIZE(stac925x_pin_nids),
5771 stac925x_pin_nids);
5772 if (err < 0)
5773 return err;
Tobin Davis8e21c342007-01-08 11:04:17 +01005774
Takashi Iwai361dab32012-05-09 14:35:27 +02005775 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01005776 spec->linear_tone_beep = 1;
Mauro Carvalho Chehab9cb36c22008-08-11 10:18:39 +02005777
Takashi Iwaid2077d42013-01-14 14:20:16 +01005778 snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl,
5779 stac925x_fixups);
Tobin Davis8e21c342007-01-08 11:04:17 +01005780
5781 spec->multiout.max_channels = 2;
5782 spec->multiout.num_dacs = 1;
5783 spec->multiout.dac_nids = stac925x_dac_nids;
5784 spec->adc_nids = stac925x_adc_nids;
5785 spec->mux_nids = stac925x_mux_nids;
5786 spec->num_muxes = 1;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02005787 spec->num_adcs = 1;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005788 spec->num_pwrs = 0;
Tobin Davis2c11f952007-05-17 09:36:34 +02005789 switch (codec->vendor_id) {
5790 case 0x83847632: /* STAC9202 */
5791 case 0x83847633: /* STAC9202D */
5792 case 0x83847636: /* STAC9251 */
5793 case 0x83847637: /* STAC9251D */
Takashi Iwaif6e98522007-10-16 14:27:04 +02005794 spec->num_dmics = STAC925X_NUM_DMICS;
Tobin Davis2c11f952007-05-17 09:36:34 +02005795 spec->dmic_nids = stac925x_dmic_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01005796 spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
5797 spec->dmux_nids = stac925x_dmux_nids;
Tobin Davis2c11f952007-05-17 09:36:34 +02005798 break;
5799 default:
5800 spec->num_dmics = 0;
5801 break;
5802 }
Tobin Davis8e21c342007-01-08 11:04:17 +01005803
Takashi Iwaid2077d42013-01-14 14:20:16 +01005804 snd_hda_add_verbs(codec, stac925x_core_init);
Tobin Davis8e21c342007-01-08 11:04:17 +01005805 spec->mixer = stac925x_mixer;
Takashi Iwai6479c632009-07-28 18:20:25 +02005806 spec->num_caps = 1;
5807 spec->capvols = stac925x_capvols;
5808 spec->capsws = stac925x_capsws;
Tobin Davis8e21c342007-01-08 11:04:17 +01005809
Takashi Iwaid2077d42013-01-14 14:20:16 +01005810 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
5811
Charles Chin9009b0e2011-11-03 10:27:27 +01005812 err = stac92xx_parse_auto_config(codec);
Takashi Iwaid2077d42013-01-14 14:20:16 +01005813 if (!err)
Takashi Iwai9e507ab2007-02-08 17:50:10 +01005814 err = -EINVAL;
Tobin Davis8e21c342007-01-08 11:04:17 +01005815 if (err < 0) {
5816 stac92xx_free(codec);
5817 return err;
5818 }
5819
5820 codec->patch_ops = stac92xx_patch_ops;
5821
Takashi Iwaid2077d42013-01-14 14:20:16 +01005822 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
5823
Tobin Davis8e21c342007-01-08 11:04:17 +01005824 return 0;
5825}
5826
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005827static int patch_stac92hd73xx(struct hda_codec *codec)
5828{
5829 struct sigmatel_spec *spec;
5830 hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
Takashi Iwai361dab32012-05-09 14:35:27 +02005831 int err;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005832 int num_dacs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005833
Takashi Iwai361dab32012-05-09 14:35:27 +02005834 err = alloc_stac_spec(codec, ARRAY_SIZE(stac92hd73xx_pin_nids),
5835 stac92hd73xx_pin_nids);
5836 if (err < 0)
5837 return err;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005838
Takashi Iwai361dab32012-05-09 14:35:27 +02005839 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01005840 spec->linear_tone_beep = 0;
Matthew Ranostaye99d32b2008-09-09 10:46:38 +02005841 codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005842 spec->board_config = snd_hda_check_board_config(codec,
5843 STAC_92HD73XX_MODELS,
5844 stac92hd73xx_models,
5845 stac92hd73xx_cfg_tbl);
Takashi Iwai842ae632009-09-02 07:43:08 +02005846 /* check codec subsystem id if not found */
5847 if (spec->board_config < 0)
5848 spec->board_config =
5849 snd_hda_check_board_codec_sid_config(codec,
5850 STAC_92HD73XX_MODELS, stac92hd73xx_models,
5851 stac92hd73xx_codec_id_cfg_tbl);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005852again:
Takashi Iwai330ee992009-02-20 14:33:36 +01005853 if (spec->board_config < 0)
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005854 snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5855 codec->chip_name);
Takashi Iwai330ee992009-02-20 14:33:36 +01005856 else
5857 stac92xx_set_config_regs(codec,
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01005858 stac92hd73xx_brd_tbl[spec->board_config]);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005859
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005860 num_dacs = snd_hda_get_connections(codec, 0x0a,
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005861 conn, STAC92HD73_DAC_COUNT + 2) - 1;
5862
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005863 if (num_dacs < 3 || num_dacs > 5) {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005864 printk(KERN_WARNING "hda_codec: Could not determine "
5865 "number of channels defaulting to DAC count\n");
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005866 num_dacs = STAC92HD73_DAC_COUNT;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005867 }
Takashi Iwaie2aec172009-09-02 01:00:05 +02005868 spec->init = stac92hd73xx_core_init;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005869 switch (num_dacs) {
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005870 case 0x3: /* 6 Channel */
Takashi Iwaid78d7a92009-03-02 14:26:25 +01005871 spec->aloopback_ctl = stac92hd73xx_6ch_loopback;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005872 break;
5873 case 0x4: /* 8 Channel */
Takashi Iwaid78d7a92009-03-02 14:26:25 +01005874 spec->aloopback_ctl = stac92hd73xx_8ch_loopback;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005875 break;
5876 case 0x5: /* 10 Channel */
Takashi Iwaid78d7a92009-03-02 14:26:25 +01005877 spec->aloopback_ctl = stac92hd73xx_10ch_loopback;
5878 break;
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01005879 }
5880 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005881
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005882 spec->aloopback_mask = 0x01;
5883 spec->aloopback_shift = 8;
5884
Matthew Ranostay1cd22242008-07-18 18:20:52 +02005885 spec->digbeep_nid = 0x1c;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005886 spec->mux_nids = stac92hd73xx_mux_nids;
5887 spec->adc_nids = stac92hd73xx_adc_nids;
5888 spec->dmic_nids = stac92hd73xx_dmic_nids;
5889 spec->dmux_nids = stac92hd73xx_dmux_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02005890 spec->smux_nids = stac92hd73xx_smux_nids;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005891
5892 spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
5893 spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
Takashi Iwai1697055e2007-12-18 18:05:52 +01005894 spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04005895
Takashi Iwai6479c632009-07-28 18:20:25 +02005896 spec->num_caps = STAC92HD73XX_NUM_CAPS;
5897 spec->capvols = stac92hd73xx_capvols;
5898 spec->capsws = stac92hd73xx_capsws;
5899
Matthew Ranostaya7662642008-02-21 07:51:14 +01005900 switch (spec->board_config) {
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05005901 case STAC_DELL_EQ:
Matthew Ranostayd654a662008-03-14 08:46:51 +01005902 spec->init = dell_eq_core_init;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05005903 /* fallthru */
Takashi Iwai661cd8f2008-11-25 15:18:29 +01005904 case STAC_DELL_M6_AMIC:
5905 case STAC_DELL_M6_DMIC:
5906 case STAC_DELL_M6_BOTH:
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04005907 spec->num_smuxes = 0;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05005908 spec->eapd_switch = 0;
Matthew Ranostay6b3ab212008-11-03 08:12:43 -05005909
Takashi Iwai661cd8f2008-11-25 15:18:29 +01005910 switch (spec->board_config) {
5911 case STAC_DELL_M6_AMIC: /* Analog Mics */
Takashi Iwai330ee992009-02-20 14:33:36 +01005912 snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
Matthew Ranostaya7662642008-02-21 07:51:14 +01005913 spec->num_dmics = 0;
5914 break;
Takashi Iwai661cd8f2008-11-25 15:18:29 +01005915 case STAC_DELL_M6_DMIC: /* Digital Mics */
Takashi Iwai330ee992009-02-20 14:33:36 +01005916 snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
Matthew Ranostaya7662642008-02-21 07:51:14 +01005917 spec->num_dmics = 1;
5918 break;
Takashi Iwai661cd8f2008-11-25 15:18:29 +01005919 case STAC_DELL_M6_BOTH: /* Both */
Takashi Iwai330ee992009-02-20 14:33:36 +01005920 snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
5921 snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
Matthew Ranostaya7662642008-02-21 07:51:14 +01005922 spec->num_dmics = 1;
5923 break;
5924 }
5925 break;
Takashi Iwai842ae632009-09-02 07:43:08 +02005926 case STAC_ALIENWARE_M17X:
5927 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
5928 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
5929 spec->eapd_switch = 0;
5930 break;
Matthew Ranostaya7662642008-02-21 07:51:14 +01005931 default:
5932 spec->num_dmics = STAC92HD73XX_NUM_DMICS;
Matthew Ranostay2a9c7812008-09-13 16:45:39 -04005933 spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids);
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05005934 spec->eapd_switch = 1;
Takashi Iwai5207e102009-07-30 13:09:08 +02005935 break;
Matthew Ranostaya7662642008-02-21 07:51:14 +01005936 }
Takashi Iwaiaf6ee302009-09-14 15:03:12 +02005937 if (spec->board_config != STAC_92HD73XX_REF) {
Matthew Ranostayb2c4f4d2008-09-26 10:06:40 -04005938 /* GPIO0 High = Enable EAPD */
5939 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
5940 spec->gpio_data = 0x01;
5941 }
Matthew Ranostaya7662642008-02-21 07:51:14 +01005942
Matthew Ranostaya64135a2008-01-10 16:55:06 +01005943 spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
5944 spec->pwr_nids = stac92hd73xx_pwr_nids;
5945
Charles Chin9009b0e2011-11-03 10:27:27 +01005946 err = stac92xx_parse_auto_config(codec);
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005947
5948 if (!err) {
5949 if (spec->board_config < 0) {
5950 printk(KERN_WARNING "hda_codec: No auto-config is "
5951 "available, default to model=ref\n");
5952 spec->board_config = STAC_92HD73XX_REF;
5953 goto again;
5954 }
5955 err = -EINVAL;
5956 }
5957
5958 if (err < 0) {
5959 stac92xx_free(codec);
5960 return err;
5961 }
5962
Takashi Iwai9e43f0d2008-12-17 14:51:01 +01005963 if (spec->board_config == STAC_92HD73XX_NO_JD)
5964 spec->hp_detect = 0;
5965
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005966 codec->patch_ops = stac92xx_patch_ops;
5967
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01005968 codec->proc_widget_hook = stac92hd7x_proc_hook;
5969
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01005970 return 0;
5971}
5972
Vitaliy Kulikovcbbf50b2011-01-14 17:21:13 -06005973static int hp_bnb2011_with_dock(struct hda_codec *codec)
Vitaliy Kulikov335e3b82010-10-22 18:38:31 -05005974{
5975 if (codec->vendor_id != 0x111d7605 &&
5976 codec->vendor_id != 0x111d76d1)
5977 return 0;
5978
5979 switch (codec->subsystem_id) {
5980 case 0x103c1618:
5981 case 0x103c1619:
5982 case 0x103c161a:
5983 case 0x103c161b:
5984 case 0x103c161c:
5985 case 0x103c161d:
5986 case 0x103c161e:
5987 case 0x103c161f:
Vitaliy Kulikov335e3b82010-10-22 18:38:31 -05005988
5989 case 0x103c162a:
5990 case 0x103c162b:
5991
5992 case 0x103c1630:
5993 case 0x103c1631:
5994
5995 case 0x103c1633:
Vitaliy Kulikovcbbf50b2011-01-14 17:21:13 -06005996 case 0x103c1634:
Vitaliy Kulikov335e3b82010-10-22 18:38:31 -05005997 case 0x103c1635:
5998
Vitaliy Kulikov335e3b82010-10-22 18:38:31 -05005999 case 0x103c3587:
6000 case 0x103c3588:
6001 case 0x103c3589:
6002 case 0x103c358a:
6003
6004 case 0x103c3667:
6005 case 0x103c3668:
Vitaliy Kulikovcbbf50b2011-01-14 17:21:13 -06006006 case 0x103c3669:
6007
6008 return 1;
Vitaliy Kulikov335e3b82010-10-22 18:38:31 -05006009 }
6010 return 0;
6011}
6012
Vitaliy Kulikov699d8992011-03-10 13:43:35 -06006013static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid)
6014{
6015 struct sigmatel_spec *spec = codec->spec;
6016 unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
6017 int i;
6018
6019 spec->auto_pin_nids[spec->auto_pin_cnt] = nid;
6020 spec->auto_pin_cnt++;
6021
6022 if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
6023 get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) {
6024 for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) {
6025 if (nid == stac92hd83xxx_dmic_nids[i]) {
6026 spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid;
6027 spec->auto_dmic_cnt++;
6028 }
6029 }
6030 }
6031}
6032
6033static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid)
6034{
6035 struct sigmatel_spec *spec = codec->spec;
6036
6037 spec->auto_adc_nids[spec->auto_adc_cnt] = nid;
6038 spec->auto_adc_cnt++;
6039}
6040
6041static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid)
6042{
6043 int i, j;
6044 struct sigmatel_spec *spec = codec->spec;
6045
6046 for (i = 0; i < spec->auto_adc_cnt; i++) {
6047 if (get_connection_index(codec,
6048 spec->auto_adc_nids[i], nid) >= 0) {
6049 /* mux and volume for adc_nids[i] */
6050 if (!spec->auto_mux_nids[i]) {
6051 spec->auto_mux_nids[i] = nid;
6052 /* 92hd codecs capture volume is in mux */
6053 spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid,
6054 3, 0, HDA_OUTPUT);
6055 }
6056 for (j = 0; j < spec->auto_dmic_cnt; j++) {
6057 if (get_connection_index(codec, nid,
6058 spec->auto_dmic_nids[j]) >= 0) {
6059 /* dmux for adc_nids[i] */
6060 if (!spec->auto_dmux_nids[i])
6061 spec->auto_dmux_nids[i] = nid;
6062 break;
6063 }
6064 }
6065 break;
6066 }
6067 }
6068}
6069
6070static void stac92hd8x_fill_auto_spec(struct hda_codec *codec)
6071{
6072 hda_nid_t nid, end_nid;
6073 unsigned int wid_caps, wid_type;
6074 struct sigmatel_spec *spec = codec->spec;
6075
6076 end_nid = codec->start_nid + codec->num_nodes;
6077
6078 for (nid = codec->start_nid; nid < end_nid; nid++) {
6079 wid_caps = get_wcaps(codec, nid);
6080 wid_type = get_wcaps_type(wid_caps);
6081
6082 if (wid_type == AC_WID_PIN)
6083 stac92hd8x_add_pin(codec, nid);
6084
6085 if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL))
6086 stac92hd8x_add_adc(codec, nid);
6087 }
6088
6089 for (nid = codec->start_nid; nid < end_nid; nid++) {
6090 wid_caps = get_wcaps(codec, nid);
6091 wid_type = get_wcaps_type(wid_caps);
6092
6093 if (wid_type == AC_WID_AUD_SEL)
6094 stac92hd8x_add_mux(codec, nid);
6095 }
6096
6097 spec->pin_nids = spec->auto_pin_nids;
6098 spec->num_pins = spec->auto_pin_cnt;
6099 spec->adc_nids = spec->auto_adc_nids;
6100 spec->num_adcs = spec->auto_adc_cnt;
6101 spec->capvols = spec->auto_capvols;
6102 spec->capsws = spec->auto_capvols;
6103 spec->num_caps = spec->auto_adc_cnt;
6104 spec->mux_nids = spec->auto_mux_nids;
6105 spec->num_muxes = spec->auto_adc_cnt;
6106 spec->dmux_nids = spec->auto_dmux_nids;
6107 spec->num_dmuxes = spec->auto_adc_cnt;
6108 spec->dmic_nids = spec->auto_dmic_nids;
6109 spec->num_dmics = spec->auto_dmic_cnt;
6110}
6111
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006112static int patch_stac92hd83xxx(struct hda_codec *codec)
6113{
6114 struct sigmatel_spec *spec;
Takashi Iwaia3e19972012-07-26 08:17:20 +02006115 int default_polarity = -1; /* no default cfg */
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006116 int err;
6117
Takashi Iwai361dab32012-05-09 14:35:27 +02006118 err = alloc_stac_spec(codec, 0, NULL); /* pins filled later */
6119 if (err < 0)
6120 return err;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006121
Vitaliy Kulikovcbbf50b2011-01-14 17:21:13 -06006122 if (hp_bnb2011_with_dock(codec)) {
6123 snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f);
6124 snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
6125 }
6126
Takashi Iwaic36b5b02012-08-28 09:20:13 -07006127 codec->epss = 0; /* longer delay needed for D3 */
Vitaliy Kulikov699d8992011-03-10 13:43:35 -06006128 stac92hd8x_fill_auto_spec(codec);
6129
Takashi Iwai361dab32012-05-09 14:35:27 +02006130 spec = codec->spec;
Takashi Iwai1db7ccdb2010-12-03 15:19:14 +01006131 spec->linear_tone_beep = 0;
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04006132 codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006133 spec->digbeep_nid = 0x21;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006134 spec->pwr_nids = stac92hd83xxx_pwr_nids;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006135 spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01006136 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006137 spec->init = stac92hd83xxx_core_init;
Takashi Iwai6479c632009-07-28 18:20:25 +02006138
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006139 spec->board_config = snd_hda_check_board_config(codec,
6140 STAC_92HD83XXX_MODELS,
6141 stac92hd83xxx_models,
6142 stac92hd83xxx_cfg_tbl);
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06006143 /* check codec subsystem id if not found */
6144 if (spec->board_config < 0)
6145 spec->board_config =
6146 snd_hda_check_board_codec_sid_config(codec,
6147 STAC_92HD83XXX_MODELS, stac92hd83xxx_models,
6148 stac92hd83xxx_codec_id_cfg_tbl);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006149again:
Takashi Iwai330ee992009-02-20 14:33:36 +01006150 if (spec->board_config < 0)
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006151 snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
6152 codec->chip_name);
Takashi Iwai330ee992009-02-20 14:33:36 +01006153 else
6154 stac92xx_set_config_regs(codec,
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01006155 stac92hd83xxx_brd_tbl[spec->board_config]);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006156
Takashi Iwaib4e81872009-11-18 17:20:24 +01006157 codec->patch_ops = stac92xx_patch_ops;
6158
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06006159 switch (spec->board_config) {
6160 case STAC_HP_ZEPHYR:
6161 spec->init = stac92hd83xxx_hp_zephyr_init;
6162 break;
Takashi Iwaia3e19972012-07-26 08:17:20 +02006163 case STAC_92HD83XXX_HP_LED:
Takashi Iwaiff8a1e22012-07-31 10:16:59 +02006164 default_polarity = 0;
6165 break;
6166 case STAC_92HD83XXX_HP_INV_LED:
Takashi Iwaia3e19972012-07-26 08:17:20 +02006167 default_polarity = 1;
6168 break;
Takashi Iwai62cbde12012-09-14 11:58:54 +02006169 case STAC_92HD83XXX_HP_MIC_LED:
6170 spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
6171 break;
David Henningsson8d032a82012-10-09 12:48:40 +02006172 case STAC_92HD83XXX_HEADSET_JACK:
6173 spec->headset_jack = 1;
6174 break;
Vitaliy Kulikov5556e142012-02-27 16:47:37 -06006175 }
6176
Takashi Iwaia3e19972012-07-26 08:17:20 +02006177 if (find_mute_led_cfg(codec, default_polarity))
Vitaliy Kulikove108c7b2010-01-28 19:21:07 +01006178 snd_printd("mute LED gpio %d polarity %d\n",
6179 spec->gpio_led,
6180 spec->gpio_led_polarity);
6181
Takashi Iwaib4e81872009-11-18 17:20:24 +01006182 if (spec->gpio_led) {
Takashi Iwaif1a73742011-12-04 13:44:06 +01006183 if (!spec->vref_mute_led_nid) {
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05006184 spec->gpio_mask |= spec->gpio_led;
6185 spec->gpio_dir |= spec->gpio_led;
6186 spec->gpio_data |= spec->gpio_led;
6187 } else {
6188 codec->patch_ops.set_power_state =
6189 stac92xx_set_power_state;
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05006190 }
Takashi Iwaib4e81872009-11-18 17:20:24 +01006191 }
Takashi Iwaib4e81872009-11-18 17:20:24 +01006192
Takashi Iwai62cbde12012-09-14 11:58:54 +02006193 if (spec->mic_mute_led_gpio) {
6194 spec->gpio_mask |= spec->mic_mute_led_gpio;
6195 spec->gpio_dir |= spec->mic_mute_led_gpio;
6196 spec->mic_mute_led_on = true;
6197 spec->gpio_data |= spec->mic_mute_led_gpio;
6198 }
6199
Charles Chin9009b0e2011-11-03 10:27:27 +01006200 err = stac92xx_parse_auto_config(codec);
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006201 if (!err) {
6202 if (spec->board_config < 0) {
6203 printk(KERN_WARNING "hda_codec: No auto-config is "
6204 "available, default to model=ref\n");
6205 spec->board_config = STAC_92HD83XXX_REF;
6206 goto again;
6207 }
6208 err = -EINVAL;
6209 }
6210
6211 if (err < 0) {
6212 stac92xx_free(codec);
6213 return err;
6214 }
6215
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01006216 codec->proc_widget_hook = stac92hd_proc_hook;
6217
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006218 return 0;
6219}
6220
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006221static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
6222 hda_nid_t dig0pin)
6223{
6224 struct sigmatel_spec *spec = codec->spec;
6225 int idx;
6226
6227 for (idx = 0; idx < spec->num_pins; idx++)
6228 if (spec->pin_nids[idx] == dig0pin)
6229 break;
6230 if ((idx + 2) >= spec->num_pins)
6231 return 0;
6232
6233 /* dig1pin case */
Takashi Iwai330ee992009-02-20 14:33:36 +01006234 if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE)
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006235 return 2;
6236
6237 /* dig0pin + dig2pin case */
Takashi Iwai330ee992009-02-20 14:33:36 +01006238 if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE)
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006239 return 2;
Takashi Iwai330ee992009-02-20 14:33:36 +01006240 if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE)
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006241 return 1;
6242 else
6243 return 0;
6244}
6245
Takashi Iwai75d1aeb2009-12-22 11:56:32 +01006246/* HP dv7 bass switch - GPIO5 */
6247#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
6248static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
6249 struct snd_ctl_elem_value *ucontrol)
6250{
6251 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6252 struct sigmatel_spec *spec = codec->spec;
6253 ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
6254 return 0;
6255}
6256
6257static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
6258 struct snd_ctl_elem_value *ucontrol)
6259{
6260 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6261 struct sigmatel_spec *spec = codec->spec;
6262 unsigned int gpio_data;
6263
6264 gpio_data = (spec->gpio_data & ~0x20) |
6265 (ucontrol->value.integer.value[0] ? 0x20 : 0);
6266 if (gpio_data == spec->gpio_data)
6267 return 0;
6268 spec->gpio_data = gpio_data;
6269 stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
6270 return 1;
6271}
6272
Takashi Iwai2b635362011-05-02 12:33:43 +02006273static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
Takashi Iwai75d1aeb2009-12-22 11:56:32 +01006274 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6275 .info = stac_hp_bass_gpio_info,
6276 .get = stac_hp_bass_gpio_get,
6277 .put = stac_hp_bass_gpio_put,
6278};
6279
6280static int stac_add_hp_bass_switch(struct hda_codec *codec)
6281{
6282 struct sigmatel_spec *spec = codec->spec;
6283
6284 if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl,
6285 "Bass Speaker Playback Switch", 0))
6286 return -ENOMEM;
6287
6288 spec->gpio_mask |= 0x20;
6289 spec->gpio_dir |= 0x20;
6290 spec->gpio_data |= 0x20;
6291 return 0;
6292}
6293
Matthew Ranostaye035b842007-11-06 11:53:55 +01006294static int patch_stac92hd71bxx(struct hda_codec *codec)
6295{
6296 struct sigmatel_spec *spec;
Takashi Iwai2b635362011-05-02 12:33:43 +02006297 const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init;
Vitaliy Kulikov5bdaaad2009-11-04 07:57:45 +01006298 unsigned int pin_cfg;
Takashi Iwai361dab32012-05-09 14:35:27 +02006299 int err;
Matthew Ranostaye035b842007-11-06 11:53:55 +01006300
Takashi Iwai361dab32012-05-09 14:35:27 +02006301 err = alloc_stac_spec(codec, STAC92HD71BXX_NUM_PINS,
6302 stac92hd71bxx_pin_nids_4port);
6303 if (err < 0)
6304 return err;
Matthew Ranostaye035b842007-11-06 11:53:55 +01006305
Takashi Iwai361dab32012-05-09 14:35:27 +02006306 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01006307 spec->linear_tone_beep = 0;
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006308 codec->patch_ops = stac92xx_patch_ops;
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -05006309 switch (codec->vendor_id) {
6310 case 0x111d76b6:
6311 case 0x111d76b7:
Herton Ronaldo Krzesinski616f89e2009-02-04 11:23:19 -05006312 break;
6313 case 0x111d7603:
6314 case 0x111d7608:
6315 /* On 92HD75Bx 0x27 isn't a pin nid */
6316 spec->num_pins--;
6317 /* fallthrough */
6318 default:
6319 spec->pin_nids = stac92hd71bxx_pin_nids_6port;
6320 }
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006321 spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
Matthew Ranostaye035b842007-11-06 11:53:55 +01006322 spec->board_config = snd_hda_check_board_config(codec,
6323 STAC_92HD71BXX_MODELS,
6324 stac92hd71bxx_models,
6325 stac92hd71bxx_cfg_tbl);
6326again:
Takashi Iwai330ee992009-02-20 14:33:36 +01006327 if (spec->board_config < 0)
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006328 snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
6329 codec->chip_name);
Takashi Iwai330ee992009-02-20 14:33:36 +01006330 else
6331 stac92xx_set_config_regs(codec,
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01006332 stac92hd71bxx_brd_tbl[spec->board_config]);
Matthew Ranostaye035b842007-11-06 11:53:55 +01006333
Takashi Iwaifc64b262009-09-14 15:33:01 +02006334 if (spec->board_config != STAC_92HD71BXX_REF) {
Takashi Iwai41c3b642008-11-18 10:45:15 +01006335 /* GPIO0 = EAPD */
6336 spec->gpio_mask = 0x01;
6337 spec->gpio_dir = 0x01;
6338 spec->gpio_data = 0x01;
6339 }
6340
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006341 spec->dmic_nids = stac92hd71bxx_dmic_nids;
6342 spec->dmux_nids = stac92hd71bxx_dmux_nids;
6343
Takashi Iwai6479c632009-07-28 18:20:25 +02006344 spec->num_caps = STAC92HD71BXX_NUM_CAPS;
6345 spec->capvols = stac92hd71bxx_capvols;
6346 spec->capsws = stac92hd71bxx_capsws;
6347
Matthew Ranostay541eee82007-12-14 12:08:04 +01006348 switch (codec->vendor_id) {
6349 case 0x111d76b6: /* 4 Port without Analog Mixer */
6350 case 0x111d76b7:
Herton Ronaldo Krzesinski23c7b522009-02-08 19:51:28 -02006351 unmute_init++;
6352 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01006353 case 0x111d76b4: /* 6 Port without Analog Mixer */
6354 case 0x111d76b5:
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04006355 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02006356 spec->num_dmics = stac92xx_connected_ports(codec,
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006357 stac92hd71bxx_dmic_nids,
6358 STAC92HD71BXX_NUM_DMICS);
Matthew Ranostay541eee82007-12-14 12:08:04 +01006359 break;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006360 case 0x111d7608: /* 5 Port with Analog Mixer */
Takashi Iwai8e5f2622008-11-15 19:28:54 +01006361 switch (spec->board_config) {
6362 case STAC_HP_M4:
Matthew Ranostay72474be2008-10-09 09:32:17 -04006363 /* Enable VREF power saving on GPIO1 detect */
Takashi Iwai3a938972011-10-28 01:16:55 +02006364 err = stac_add_event(codec, codec->afg,
Takashi Iwaic6e4c662008-11-25 11:58:19 +01006365 STAC_VREF_EVENT, 0x02);
6366 if (err < 0)
6367 return err;
Takashi Iwaic5d08bb2008-11-18 10:55:36 +01006368 snd_hda_codec_write_cache(codec, codec->afg, 0,
Matthew Ranostay72474be2008-10-09 09:32:17 -04006369 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
Takashi Iwai3a938972011-10-28 01:16:55 +02006370 snd_hda_jack_detect_enable(codec, codec->afg, 0);
Matthew Ranostay72474be2008-10-09 09:32:17 -04006371 spec->gpio_mask |= 0x02;
6372 break;
6373 }
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006374 if ((codec->revision_id & 0xf) == 0 ||
Takashi Iwai8c2f7672008-12-01 11:54:35 +01006375 (codec->revision_id & 0xf) == 1)
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006376 spec->stream_delay = 40; /* 40 milliseconds */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006377
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006378 /* disable VSW */
Matthew Ranostayca8d33f2009-01-26 09:33:52 -05006379 unmute_init++;
Takashi Iwai330ee992009-02-20 14:33:36 +01006380 snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
6381 snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
Takashi Iwai2b635362011-05-02 12:33:43 +02006382 spec->dmic_nids = stac92hd71bxx_dmic_5port_nids;
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02006383 spec->num_dmics = stac92xx_connected_ports(codec,
Takashi Iwai2b635362011-05-02 12:33:43 +02006384 stac92hd71bxx_dmic_5port_nids,
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006385 STAC92HD71BXX_NUM_DMICS - 1);
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006386 break;
6387 case 0x111d7603: /* 6 Port with Analog Mixer */
Takashi Iwai8c2f7672008-12-01 11:54:35 +01006388 if ((codec->revision_id & 0xf) == 1)
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006389 spec->stream_delay = 40; /* 40 milliseconds */
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006390
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006391 /* fallthru */
Matthew Ranostay541eee82007-12-14 12:08:04 +01006392 default:
Matthew Ranostay0ffa9802008-09-08 11:20:05 -04006393 codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02006394 spec->num_dmics = stac92xx_connected_ports(codec,
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006395 stac92hd71bxx_dmic_nids,
6396 STAC92HD71BXX_NUM_DMICS);
Takashi Iwai5207e102009-07-30 13:09:08 +02006397 break;
Matthew Ranostay541eee82007-12-14 12:08:04 +01006398 }
6399
David Henningsson5e68fb32012-08-16 14:11:09 +02006400 if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB)
6401 spec->init = stac92hd71bxx_core_init;
6402
Matthew Ranostayca8d33f2009-01-26 09:33:52 -05006403 if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
6404 snd_hda_sequence_write_cache(codec, unmute_init);
6405
Takashi Iwaid78d7a92009-03-02 14:26:25 +01006406 spec->aloopback_ctl = stac92hd71bxx_loopback;
Matthew Ranostay4b33c762008-10-10 09:07:23 -04006407 spec->aloopback_mask = 0x50;
Matthew Ranostay541eee82007-12-14 12:08:04 +01006408 spec->aloopback_shift = 0;
6409
Matthew Ranostay8daaaa92008-08-15 07:45:52 +02006410 spec->powerdown_adcs = 1;
Matthew Ranostay1cd22242008-07-18 18:20:52 +02006411 spec->digbeep_nid = 0x26;
Matthew Ranostaye035b842007-11-06 11:53:55 +01006412 spec->mux_nids = stac92hd71bxx_mux_nids;
6413 spec->adc_nids = stac92hd71bxx_adc_nids;
Matthew Ranostayd9737752008-09-07 12:03:41 +02006414 spec->smux_nids = stac92hd71bxx_smux_nids;
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006415 spec->pwr_nids = stac92hd71bxx_pwr_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01006416
6417 spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
6418 spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
Takashi Iwai5207e102009-07-30 13:09:08 +02006419 spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
Herton Ronaldo Krzesinski6df703a2009-02-04 11:34:22 -05006420 spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e);
Matthew Ranostaye035b842007-11-06 11:53:55 +01006421
Kunal Gangakhedkard38cce72010-01-15 21:01:47 +05306422 snd_printdd("Found board config: %d\n", spec->board_config);
6423
Matthew Ranostay6a14f582008-09-12 12:02:30 -04006424 switch (spec->board_config) {
6425 case STAC_HP_M4:
Matthew Ranostay6a14f582008-09-12 12:02:30 -04006426 /* enable internal microphone */
Takashi Iwai330ee992009-02-20 14:33:36 +01006427 snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
Matthew Ranostayb9aea712008-10-09 08:37:28 -04006428 stac92xx_auto_set_pinctl(codec, 0x0e,
6429 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80);
Matthew Ranostay3a7abfd2008-11-20 21:21:43 -05006430 /* fallthru */
6431 case STAC_DELL_M4_2:
6432 spec->num_dmics = 0;
6433 spec->num_smuxes = 0;
6434 spec->num_dmuxes = 0;
6435 break;
6436 case STAC_DELL_M4_1:
6437 case STAC_DELL_M4_3:
6438 spec->num_dmics = 1;
6439 spec->num_smuxes = 0;
Takashi Iwaiea18aa42009-02-27 17:36:33 +01006440 spec->num_dmuxes = 1;
Matthew Ranostay6a14f582008-09-12 12:02:30 -04006441 break;
James Gardiner514bf542009-05-03 04:00:44 -04006442 case STAC_HP_DV4_1222NR:
6443 spec->num_dmics = 1;
6444 /* I don't know if it needs 1 or 2 smuxes - will wait for
6445 * bug reports to fix if needed
6446 */
6447 spec->num_smuxes = 1;
6448 spec->num_dmuxes = 1;
James Gardiner514bf542009-05-03 04:00:44 -04006449 /* fallthrough */
Takashi Iwai2a6ce6e2010-05-12 10:16:20 +02006450 case STAC_HP_DV4:
6451 spec->gpio_led = 0x01;
6452 /* fallthrough */
Herton Ronaldo Krzesinskie2ea57a2009-02-16 10:23:00 +01006453 case STAC_HP_DV5:
Takashi Iwai330ee992009-02-20 14:33:36 +01006454 snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
Herton Ronaldo Krzesinskie2ea57a2009-02-16 10:23:00 +01006455 stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN);
Takashi Iwai6e34c032009-09-14 15:42:18 +02006456 /* HP dv6 gives the headphone pin as a line-out. Thus we
6457 * need to set hp_detect flag here to force to enable HP
6458 * detection.
6459 */
6460 spec->hp_detect = 1;
Herton Ronaldo Krzesinskie2ea57a2009-02-16 10:23:00 +01006461 break;
Christoph Plattnerae6241f2009-03-08 23:19:05 +01006462 case STAC_HP_HDX:
6463 spec->num_dmics = 1;
6464 spec->num_dmuxes = 1;
6465 spec->num_smuxes = 1;
Takashi Iwai26ebe0a2010-05-11 08:36:29 +02006466 spec->gpio_led = 0x08;
Takashi Iwai86d190e2009-05-26 15:18:58 +02006467 break;
6468 }
Christoph Plattner443e26d2009-03-10 00:05:56 +01006469
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01006470 if (hp_blike_system(codec->subsystem_id)) {
Vitaliy Kulikov5bdaaad2009-11-04 07:57:45 +01006471 pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
6472 if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
6473 get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER ||
6474 get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) {
6475 /* It was changed in the BIOS to just satisfy MS DTM.
6476 * Lets turn it back into slaved HP
6477 */
6478 pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE))
6479 | (AC_JACK_HP_OUT <<
6480 AC_DEFCFG_DEVICE_SHIFT);
6481 pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC
6482 | AC_DEFCFG_SEQUENCE)))
6483 | 0x1f;
6484 snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg);
6485 }
6486 }
6487
Vitaliy Kulikov6a557c92011-12-12 17:35:13 -06006488 if (find_mute_led_cfg(codec, 1))
Vitaliy Kulikovc357aab2009-12-11 07:51:54 +01006489 snd_printd("mute LED gpio %d polarity %d\n",
6490 spec->gpio_led,
6491 spec->gpio_led_polarity);
Vitaliy Kulikov5bdaaad2009-11-04 07:57:45 +01006492
Takashi Iwai86d190e2009-05-26 15:18:58 +02006493 if (spec->gpio_led) {
Takashi Iwaif1a73742011-12-04 13:44:06 +01006494 if (!spec->vref_mute_led_nid) {
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05006495 spec->gpio_mask |= spec->gpio_led;
6496 spec->gpio_dir |= spec->gpio_led;
6497 spec->gpio_data |= spec->gpio_led;
6498 } else {
6499 codec->patch_ops.set_power_state =
6500 stac92xx_set_power_state;
Vitaliy Kulikov45eebda2011-07-26 16:56:20 -05006501 }
Takashi Iwai86d190e2009-05-26 15:18:58 +02006502 }
Matthew Ranostay6a14f582008-09-12 12:02:30 -04006503
Takashi Iwaic21ca4a2008-12-19 09:26:08 +01006504 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostaye035b842007-11-06 11:53:55 +01006505
Charles Chin9009b0e2011-11-03 10:27:27 +01006506 err = stac92xx_parse_auto_config(codec);
Matthew Ranostaye035b842007-11-06 11:53:55 +01006507 if (!err) {
6508 if (spec->board_config < 0) {
6509 printk(KERN_WARNING "hda_codec: No auto-config is "
6510 "available, default to model=ref\n");
6511 spec->board_config = STAC_92HD71BXX_REF;
6512 goto again;
6513 }
6514 err = -EINVAL;
6515 }
6516
6517 if (err < 0) {
6518 stac92xx_free(codec);
6519 return err;
6520 }
6521
Takashi Iwai75d1aeb2009-12-22 11:56:32 +01006522 /* enable bass on HP dv7 */
Takashi Iwai2a6ce6e2010-05-12 10:16:20 +02006523 if (spec->board_config == STAC_HP_DV4 ||
6524 spec->board_config == STAC_HP_DV5) {
Takashi Iwai75d1aeb2009-12-22 11:56:32 +01006525 unsigned int cap;
6526 cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
6527 cap &= AC_GPIO_IO_COUNT;
6528 if (cap >= 6)
6529 stac_add_hp_bass_switch(codec);
6530 }
6531
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01006532 codec->proc_widget_hook = stac92hd7x_proc_hook;
6533
Matthew Ranostaye035b842007-11-06 11:53:55 +01006534 return 0;
Takashi Iwai86d190e2009-05-26 15:18:58 +02006535}
Matthew Ranostaye035b842007-11-06 11:53:55 +01006536
Matt2f2f4252005-04-13 14:45:30 +02006537static int patch_stac922x(struct hda_codec *codec)
6538{
6539 struct sigmatel_spec *spec;
Mattc7d4b2f2005-06-27 14:59:41 +02006540 int err;
Matt2f2f4252005-04-13 14:45:30 +02006541
Takashi Iwai361dab32012-05-09 14:35:27 +02006542 err = alloc_stac_spec(codec, ARRAY_SIZE(stac922x_pin_nids),
6543 stac922x_pin_nids);
6544 if (err < 0)
6545 return err;
Matt2f2f4252005-04-13 14:45:30 +02006546
Takashi Iwai361dab32012-05-09 14:35:27 +02006547 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01006548 spec->linear_tone_beep = 1;
Ivan N. Zlatev5d5d3bc2007-05-29 16:03:00 +02006549
Takashi Iwai0a427842013-01-14 15:20:13 +01006550 snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl,
6551 stac922x_fixups);
Matt2f2f4252005-04-13 14:45:30 +02006552
Matt2f2f4252005-04-13 14:45:30 +02006553 spec->adc_nids = stac922x_adc_nids;
6554 spec->mux_nids = stac922x_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01006555 spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02006556 spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
Matt Porter8b657272006-10-26 17:12:59 +02006557 spec->num_dmics = 0;
Matthew Ranostaya64135a2008-01-10 16:55:06 +01006558 spec->num_pwrs = 0;
Mattc7d4b2f2005-06-27 14:59:41 +02006559
Takashi Iwai6479c632009-07-28 18:20:25 +02006560 spec->num_caps = STAC922X_NUM_CAPS;
6561 spec->capvols = stac922x_capvols;
6562 spec->capsws = stac922x_capsws;
Mattc7d4b2f2005-06-27 14:59:41 +02006563
6564 spec->multiout.dac_nids = spec->dac_nids;
Takashi Iwai19039bd2006-06-28 15:52:16 +02006565
Takashi Iwai0a427842013-01-14 15:20:13 +01006566 snd_hda_add_verbs(codec, stac922x_core_init);
6567
6568 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
6569
Charles Chin9009b0e2011-11-03 10:27:27 +01006570 err = stac92xx_parse_auto_config(codec);
Takashi Iwai0a427842013-01-14 15:20:13 +01006571 if (!err)
Takashi Iwai9e507ab2007-02-08 17:50:10 +01006572 err = -EINVAL;
Matt Porter3cc08dc2006-01-23 15:27:49 +01006573 if (err < 0) {
6574 stac92xx_free(codec);
6575 return err;
6576 }
6577
6578 codec->patch_ops = stac92xx_patch_ops;
6579
Takashi Iwai807a46362007-05-29 19:01:37 +02006580 /* Fix Mux capture level; max to 2 */
6581 snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
6582 (0 << AC_AMPCAP_OFFSET_SHIFT) |
6583 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
6584 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
6585 (0 << AC_AMPCAP_MUTE_SHIFT));
6586
Takashi Iwai0a427842013-01-14 15:20:13 +01006587 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
6588
Matt Porter3cc08dc2006-01-23 15:27:49 +01006589 return 0;
6590}
6591
6592static int patch_stac927x(struct hda_codec *codec)
6593{
6594 struct sigmatel_spec *spec;
6595 int err;
6596
Takashi Iwai361dab32012-05-09 14:35:27 +02006597 err = alloc_stac_spec(codec, ARRAY_SIZE(stac927x_pin_nids),
6598 stac927x_pin_nids);
6599 if (err < 0)
6600 return err;
Matt Porter3cc08dc2006-01-23 15:27:49 +01006601
Takashi Iwai361dab32012-05-09 14:35:27 +02006602 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01006603 spec->linear_tone_beep = 1;
Matthew Ranostay45c1d852009-02-04 17:49:41 -05006604 codec->slave_dig_outs = stac927x_slave_dig_outs;
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006605 spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
6606 stac927x_models,
6607 stac927x_cfg_tbl);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01006608 again:
Takashi Iwai330ee992009-02-20 14:33:36 +01006609 if (spec->board_config < 0)
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006610 snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
6611 codec->chip_name);
Takashi Iwai330ee992009-02-20 14:33:36 +01006612 else
6613 stac92xx_set_config_regs(codec,
Takashi Iwaiaf9f3412008-11-18 10:38:56 +01006614 stac927x_brd_tbl[spec->board_config]);
Matt Porter3cc08dc2006-01-23 15:27:49 +01006615
Matthew Ranostay1cd22242008-07-18 18:20:52 +02006616 spec->digbeep_nid = 0x23;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006617 spec->adc_nids = stac927x_adc_nids;
6618 spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
6619 spec->mux_nids = stac927x_mux_nids;
6620 spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02006621 spec->smux_nids = stac927x_smux_nids;
6622 spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids);
Matthew Ranostay65973632008-09-16 10:39:37 -04006623 spec->spdif_labels = stac927x_spdif_labels;
Matthew Ranostayb76c8502008-02-06 14:49:44 +01006624 spec->dac_list = stac927x_dac_nids;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006625 spec->multiout.dac_nids = spec->dac_nids;
6626
Takashi Iwaiaf6ee302009-09-14 15:03:12 +02006627 if (spec->board_config != STAC_D965_REF) {
6628 /* GPIO0 High = Enable EAPD */
6629 spec->eapd_mask = spec->gpio_mask = 0x01;
6630 spec->gpio_dir = spec->gpio_data = 0x01;
6631 }
6632
Tobin Davis81d3dbd2006-08-22 19:44:45 +02006633 switch (spec->board_config) {
Tobin Davis93ed1502006-09-01 21:03:12 +02006634 case STAC_D965_3ST:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006635 case STAC_D965_5ST:
6636 /* GPIO0 High = Enable EAPD */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006637 spec->num_dmics = 0;
Tobin Davis93ed1502006-09-01 21:03:12 +02006638 spec->init = d965_core_init;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02006639 break;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006640 case STAC_DELL_BIOS:
Matthew Ranostay780c8be2008-04-14 13:32:27 +02006641 switch (codec->subsystem_id) {
6642 case 0x10280209:
6643 case 0x1028022e:
6644 /* correct the device field to SPDIF out */
Takashi Iwai330ee992009-02-20 14:33:36 +01006645 snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070);
Matthew Ranostay780c8be2008-04-14 13:32:27 +02006646 break;
Takashi Iwai86d190e2009-05-26 15:18:58 +02006647 }
Matthew Ranostay03d7ca12008-02-21 07:51:46 +01006648 /* configure the analog microphone on some laptops */
Takashi Iwai330ee992009-02-20 14:33:36 +01006649 snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130);
Matthew Ranostay2f32d902008-01-10 13:06:26 +01006650 /* correct the front output jack as a hp out */
Takashi Iwai330ee992009-02-20 14:33:36 +01006651 snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01006652 /* correct the front input jack as a mic */
Takashi Iwai330ee992009-02-20 14:33:36 +01006653 snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130);
Matthew Ranostayc481fca2008-01-07 12:18:28 +01006654 /* fallthru */
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006655 case STAC_DELL_3ST:
Takashi Iwaiaf6ee302009-09-14 15:03:12 +02006656 if (codec->subsystem_id != 0x1028022f) {
6657 /* GPIO2 High = Enable EAPD */
6658 spec->eapd_mask = spec->gpio_mask = 0x04;
6659 spec->gpio_dir = spec->gpio_data = 0x04;
6660 }
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006661 spec->dmic_nids = stac927x_dmic_nids;
6662 spec->num_dmics = STAC927X_NUM_DMICS;
6663
Takashi Iwaiccca7cd2009-10-13 15:32:21 +02006664 spec->init = dell_3st_core_init;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006665 spec->dmux_nids = stac927x_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01006666 spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
Tobin Davis81d3dbd2006-08-22 19:44:45 +02006667 break;
Takashi Iwai54930532009-10-11 17:38:29 +02006668 case STAC_927X_VOLKNOB:
6669 spec->num_dmics = 0;
6670 spec->init = stac927x_volknob_core_init;
6671 break;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02006672 default:
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006673 spec->num_dmics = 0;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02006674 spec->init = stac927x_core_init;
Takashi Iwaiaf6ee302009-09-14 15:03:12 +02006675 break;
Tobin Davis81d3dbd2006-08-22 19:44:45 +02006676 }
Matt Porter3cc08dc2006-01-23 15:27:49 +01006677
Takashi Iwai6479c632009-07-28 18:20:25 +02006678 spec->num_caps = STAC927X_NUM_CAPS;
6679 spec->capvols = stac927x_capvols;
6680 spec->capsws = stac927x_capsws;
6681
Matthew Ranostaya64135a2008-01-10 16:55:06 +01006682 spec->num_pwrs = 0;
Takashi Iwaid78d7a92009-03-02 14:26:25 +01006683 spec->aloopback_ctl = stac927x_loopback;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01006684 spec->aloopback_mask = 0x40;
6685 spec->aloopback_shift = 0;
Matthew Ranostayc0cea0d2008-11-16 11:42:34 -05006686 spec->eapd_switch = 1;
Matthew Ranostay8e9068b2007-12-17 11:58:13 +01006687
Charles Chin9009b0e2011-11-03 10:27:27 +01006688 err = stac92xx_parse_auto_config(codec);
Takashi Iwai9e507ab2007-02-08 17:50:10 +01006689 if (!err) {
6690 if (spec->board_config < 0) {
6691 printk(KERN_WARNING "hda_codec: No auto-config is "
6692 "available, default to model=ref\n");
6693 spec->board_config = STAC_D965_REF;
6694 goto again;
6695 }
6696 err = -EINVAL;
6697 }
Mattc7d4b2f2005-06-27 14:59:41 +02006698 if (err < 0) {
6699 stac92xx_free(codec);
6700 return err;
6701 }
Matt2f2f4252005-04-13 14:45:30 +02006702
6703 codec->patch_ops = stac92xx_patch_ops;
6704
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01006705 codec->proc_widget_hook = stac927x_proc_hook;
6706
Takashi Iwai52987652008-01-16 16:09:47 +01006707 /*
6708 * !!FIXME!!
6709 * The STAC927x seem to require fairly long delays for certain
6710 * command sequences. With too short delays (even if the answer
6711 * is set to RIRB properly), it results in the silence output
6712 * on some hardwares like Dell.
6713 *
6714 * The below flag enables the longer delay (see get_response
6715 * in hda_intel.c).
6716 */
6717 codec->bus->needs_damn_long_delay = 1;
6718
Takashi Iwaie28d8322008-12-17 13:48:29 +01006719 /* no jack detecion for ref-no-jd model */
6720 if (spec->board_config == STAC_D965_REF_NO_JD)
6721 spec->hp_detect = 0;
6722
Matt2f2f4252005-04-13 14:45:30 +02006723 return 0;
6724}
6725
Matt Porterf3302a52006-07-31 12:49:34 +02006726static int patch_stac9205(struct hda_codec *codec)
6727{
6728 struct sigmatel_spec *spec;
Takashi Iwai82599802007-07-31 15:56:24 +02006729 int err;
Matt Porterf3302a52006-07-31 12:49:34 +02006730
Takashi Iwai361dab32012-05-09 14:35:27 +02006731 err = alloc_stac_spec(codec, ARRAY_SIZE(stac9205_pin_nids),
6732 stac9205_pin_nids);
6733 if (err < 0)
6734 return err;
Matt Porterf3302a52006-07-31 12:49:34 +02006735
Takashi Iwai361dab32012-05-09 14:35:27 +02006736 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01006737 spec->linear_tone_beep = 1;
Takashi Iwaife6322c2013-01-14 14:46:51 +01006738
6739 snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl,
6740 stac9205_fixups);
Matt Porterf3302a52006-07-31 12:49:34 +02006741
Matthew Ranostay1cd22242008-07-18 18:20:52 +02006742 spec->digbeep_nid = 0x23;
Matt Porterf3302a52006-07-31 12:49:34 +02006743 spec->adc_nids = stac9205_adc_nids;
Maxim Levitsky9e05b7a2007-09-03 15:31:02 +02006744 spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids);
Matt Porterf3302a52006-07-31 12:49:34 +02006745 spec->mux_nids = stac9205_mux_nids;
Takashi Iwai25494132007-03-12 12:36:16 +01006746 spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
Matthew Ranostayd9737752008-09-07 12:03:41 +02006747 spec->smux_nids = stac9205_smux_nids;
6748 spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids);
Matt Porter8b657272006-10-26 17:12:59 +02006749 spec->dmic_nids = stac9205_dmic_nids;
Takashi Iwaif6e98522007-10-16 14:27:04 +02006750 spec->num_dmics = STAC9205_NUM_DMICS;
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01006751 spec->dmux_nids = stac9205_dmux_nids;
Takashi Iwai1697055e2007-12-18 18:05:52 +01006752 spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
Matthew Ranostaya64135a2008-01-10 16:55:06 +01006753 spec->num_pwrs = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02006754
Takashi Iwaife6322c2013-01-14 14:46:51 +01006755 snd_hda_add_verbs(codec, stac9205_core_init);
Takashi Iwaid78d7a92009-03-02 14:26:25 +01006756 spec->aloopback_ctl = stac9205_loopback;
Matt Porterf3302a52006-07-31 12:49:34 +02006757
Takashi Iwai6479c632009-07-28 18:20:25 +02006758 spec->num_caps = STAC9205_NUM_CAPS;
6759 spec->capvols = stac9205_capvols;
6760 spec->capsws = stac9205_capsws;
6761
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01006762 spec->aloopback_mask = 0x40;
6763 spec->aloopback_shift = 0;
Matt Porterf3302a52006-07-31 12:49:34 +02006764 spec->multiout.dac_nids = spec->dac_nids;
Matthew Ranostay87d48362007-07-17 11:52:24 +02006765
Takashi Iwaife6322c2013-01-14 14:46:51 +01006766 /* GPIO0 High = EAPD */
6767 spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
6768 spec->gpio_data = 0x01;
Matt Porter33382402006-12-18 13:17:28 +01006769
Takashi Iwaife6322c2013-01-14 14:46:51 +01006770 /* Turn on/off EAPD per HP plugging */
6771 spec->eapd_switch = 1;
Matthew Ranostay4fe51952008-01-29 15:28:44 +01006772
Takashi Iwaife6322c2013-01-14 14:46:51 +01006773 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
Matthew Ranostay87d48362007-07-17 11:52:24 +02006774
Charles Chin9009b0e2011-11-03 10:27:27 +01006775 err = stac92xx_parse_auto_config(codec);
Takashi Iwaife6322c2013-01-14 14:46:51 +01006776 if (!err)
Takashi Iwai9e507ab2007-02-08 17:50:10 +01006777 err = -EINVAL;
Matt Porterf3302a52006-07-31 12:49:34 +02006778 if (err < 0) {
6779 stac92xx_free(codec);
6780 return err;
6781 }
6782
6783 codec->patch_ops = stac92xx_patch_ops;
6784
Takashi Iwai2d34e1b2008-11-28 14:35:16 +01006785 codec->proc_widget_hook = stac9205_proc_hook;
6786
Takashi Iwaife6322c2013-01-14 14:46:51 +01006787 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
6788
Matt Porterf3302a52006-07-31 12:49:34 +02006789 return 0;
6790}
6791
Matt2f2f4252005-04-13 14:45:30 +02006792/*
Guillaume Munch6d859062006-08-22 17:15:47 +02006793 * STAC9872 hack
Takashi Iwaidb064e52006-03-16 16:04:58 +01006794 */
6795
Takashi Iwai2b635362011-05-02 12:33:43 +02006796static const struct hda_verb stac9872_core_init[] = {
Takashi Iwai1624cb92007-07-05 13:10:51 +02006797 {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
Takashi Iwaidb064e52006-03-16 16:04:58 +01006798 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
6799 {}
6800};
6801
Takashi Iwai2b635362011-05-02 12:33:43 +02006802static const hda_nid_t stac9872_pin_nids[] = {
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006803 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
6804 0x11, 0x13, 0x14,
6805};
6806
Takashi Iwai2b635362011-05-02 12:33:43 +02006807static const hda_nid_t stac9872_adc_nids[] = {
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006808 0x8 /*,0x6*/
6809};
6810
Takashi Iwai2b635362011-05-02 12:33:43 +02006811static const hda_nid_t stac9872_mux_nids[] = {
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006812 0x15
6813};
6814
Takashi Iwai2b635362011-05-02 12:33:43 +02006815static const unsigned long stac9872_capvols[] = {
Takashi Iwai6479c632009-07-28 18:20:25 +02006816 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
6817};
6818#define stac9872_capsws stac9872_capvols
6819
Takashi Iwaifc268c12013-01-14 14:29:36 +01006820static const struct hda_pintbl stac9872_vaio_pin_configs[] = {
6821 { 0x0a, 0x03211020 },
6822 { 0x0b, 0x411111f0 },
6823 { 0x0c, 0x411111f0 },
6824 { 0x0d, 0x03a15030 },
6825 { 0x0e, 0x411111f0 },
6826 { 0x0f, 0x90170110 },
6827 { 0x11, 0x411111f0 },
6828 { 0x13, 0x411111f0 },
6829 { 0x14, 0x90a7013e },
6830 {}
Takashi Iwai307282c2009-03-12 18:17:58 +01006831};
6832
Takashi Iwaifc268c12013-01-14 14:29:36 +01006833static const struct hda_model_fixup stac9872_models[] = {
6834 { .id = STAC_9872_VAIO, .name = "vaio" },
6835 {}
Takashi Iwai307282c2009-03-12 18:17:58 +01006836};
6837
Takashi Iwaifc268c12013-01-14 14:29:36 +01006838static const struct hda_fixup stac9872_fixups[] = {
6839 [STAC_9872_VAIO] = {
6840 .type = HDA_FIXUP_PINS,
6841 .v.pins = stac9872_vaio_pin_configs,
6842 },
Takashi Iwai307282c2009-03-12 18:17:58 +01006843};
6844
Takashi Iwaifc268c12013-01-14 14:29:36 +01006845static const struct snd_pci_quirk stac9872_fixup_tbl[] = {
Takashi Iwaib04add92009-07-20 08:01:36 +02006846 SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
6847 "Sony VAIO F/S", STAC_9872_VAIO),
Takashi Iwai307282c2009-03-12 18:17:58 +01006848 {} /* terminator */
6849};
6850
Guillaume Munch6d859062006-08-22 17:15:47 +02006851static int patch_stac9872(struct hda_codec *codec)
Takashi Iwaidb064e52006-03-16 16:04:58 +01006852{
6853 struct sigmatel_spec *spec;
Takashi Iwai1e137f92009-01-21 07:41:22 +01006854 int err;
Takashi Iwaidb064e52006-03-16 16:04:58 +01006855
Takashi Iwai361dab32012-05-09 14:35:27 +02006856 err = alloc_stac_spec(codec, ARRAY_SIZE(stac9872_pin_nids),
6857 stac9872_pin_nids);
6858 if (err < 0)
6859 return err;
6860
6861 spec = codec->spec;
Daniel J Blueman1b0e3722010-08-03 11:09:13 +01006862 spec->linear_tone_beep = 1;
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006863
Takashi Iwaifc268c12013-01-14 14:29:36 +01006864 snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl,
6865 stac9872_fixups);
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006866
Takashi Iwai1e137f92009-01-21 07:41:22 +01006867 spec->multiout.dac_nids = spec->dac_nids;
6868 spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids);
6869 spec->adc_nids = stac9872_adc_nids;
6870 spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids);
6871 spec->mux_nids = stac9872_mux_nids;
Takashi Iwai6479c632009-07-28 18:20:25 +02006872 spec->num_caps = 1;
6873 spec->capvols = stac9872_capvols;
6874 spec->capsws = stac9872_capsws;
Takashi Iwaifc268c12013-01-14 14:29:36 +01006875 snd_hda_add_verbs(codec, stac9872_core_init);
6876
6877 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006878
Charles Chin9009b0e2011-11-03 10:27:27 +01006879 err = stac92xx_parse_auto_config(codec);
Takashi Iwai1e137f92009-01-21 07:41:22 +01006880 if (err < 0) {
6881 stac92xx_free(codec);
6882 return -EINVAL;
Takashi Iwaicaa10b62009-01-20 17:19:01 +01006883 }
Takashi Iwai1e137f92009-01-21 07:41:22 +01006884 spec->input_mux = &spec->private_imux;
6885 codec->patch_ops = stac92xx_patch_ops;
Takashi Iwaifc268c12013-01-14 14:29:36 +01006886
6887 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
6888
Takashi Iwaidb064e52006-03-16 16:04:58 +01006889 return 0;
6890}
6891
6892
6893/*
Matt2f2f4252005-04-13 14:45:30 +02006894 * patch entries
6895 */
Takashi Iwai2b635362011-05-02 12:33:43 +02006896static const struct hda_codec_preset snd_hda_preset_sigmatel[] = {
Matt2f2f4252005-04-13 14:45:30 +02006897 { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 },
6898 { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x },
6899 { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x },
6900 { .id = 0x83847880, .name = "STAC9220 A2", .patch = patch_stac922x },
6901 { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
6902 { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
6903 { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
Matt Porter22a27c72006-07-06 18:49:10 +02006904 { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x },
6905 { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x },
6906 { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x },
6907 { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x },
6908 { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x },
6909 { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x },
Matt Porter3cc08dc2006-01-23 15:27:49 +01006910 { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
6911 { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
6912 { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
6913 { .id = 0x83847623, .name = "STAC9273D", .patch = patch_stac927x },
6914 { .id = 0x83847624, .name = "STAC9272X", .patch = patch_stac927x },
6915 { .id = 0x83847625, .name = "STAC9272D", .patch = patch_stac927x },
6916 { .id = 0x83847626, .name = "STAC9271X", .patch = patch_stac927x },
6917 { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
6918 { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
6919 { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
Tobin Davis8e21c342007-01-08 11:04:17 +01006920 { .id = 0x83847632, .name = "STAC9202", .patch = patch_stac925x },
6921 { .id = 0x83847633, .name = "STAC9202D", .patch = patch_stac925x },
6922 { .id = 0x83847634, .name = "STAC9250", .patch = patch_stac925x },
6923 { .id = 0x83847635, .name = "STAC9250D", .patch = patch_stac925x },
6924 { .id = 0x83847636, .name = "STAC9251", .patch = patch_stac925x },
6925 { .id = 0x83847637, .name = "STAC9250D", .patch = patch_stac925x },
Takashi Iwai7bd3c0f2008-05-02 12:28:02 +02006926 { .id = 0x83847645, .name = "92HD206X", .patch = patch_stac927x },
6927 { .id = 0x83847646, .name = "92HD206D", .patch = patch_stac927x },
Guillaume Munch6d859062006-08-22 17:15:47 +02006928 /* The following does not take into account .id=0x83847661 when subsys =
6929 * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
6930 * currently not fully supported.
6931 */
6932 { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 },
6933 { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
6934 { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
Simos Xenitellisa5c0f882009-06-10 16:33:31 +01006935 { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 },
Matt Porterf3302a52006-07-31 12:49:34 +02006936 { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
6937 { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
6938 { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
6939 { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
6940 { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 },
6941 { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
6942 { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
6943 { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006944 { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006945 { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
Vitaliy Kulikova9694fa2010-02-04 08:58:23 +01006946 { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx},
Matthew Ranostayd0513fc2008-07-27 10:30:30 +02006947 { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
Matthew Ranostayff2e7332009-04-01 14:49:48 -04006948 { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
Charles Chin8a345a02010-08-10 11:43:25 +02006949 { .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx},
6950 { .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx},
Charles Chin36706002010-01-29 12:05:51 +01006951 { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx},
6952 { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx},
6953 { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx},
6954 { .id = 0x111d7669, .name = "92HD88B4", .patch = patch_stac92hd83xxx},
Matthew Ranostayaafc4412008-06-13 18:04:33 +02006955 { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
Matthew Ranostay541eee82007-12-14 12:08:04 +01006956 { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
6957 { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
Matthew Ranostaye1f0d662007-12-13 17:47:21 +01006958 { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
Matthew Ranostay541eee82007-12-14 12:08:04 +01006959 { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
6960 { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
6961 { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
6962 { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
6963 { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
6964 { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
6965 { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
6966 { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
Charles Chin4d8ec5f2010-08-19 08:06:16 +02006967 { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx },
6968 { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx },
6969 { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx },
6970 { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx },
6971 { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx },
6972 { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx },
6973 { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx },
6974 { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx },
6975 { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx },
6976 { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx },
6977 { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx },
6978 { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx },
6979 { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
6980 { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
6981 { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
David Henningsson46724c22011-09-20 09:02:22 +02006982 { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx},
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02006983 { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
Vitaliy Kulikov4dfb8a42011-02-22 17:32:19 -06006984 { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
6985 { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
Vitaliy Kulikovab5a6eb2010-09-08 09:00:17 +02006986 { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
Charles Chinad5d8752011-11-02 07:56:58 +01006987 { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx},
6988 { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx},
6989 { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx},
6990 { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx},
6991 { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx},
6992 { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx},
6993 { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx},
6994 { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx},
6995 { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx},
6996 { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx},
6997 { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx},
6998 { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx},
Matt2f2f4252005-04-13 14:45:30 +02006999 {} /* terminator */
7000};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01007001
7002MODULE_ALIAS("snd-hda-codec-id:8384*");
7003MODULE_ALIAS("snd-hda-codec-id:111d*");
7004
7005MODULE_LICENSE("GPL");
7006MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
7007
7008static struct hda_codec_preset_list sigmatel_list = {
7009 .preset = snd_hda_preset_sigmatel,
7010 .owner = THIS_MODULE,
7011};
7012
7013static int __init patch_sigmatel_init(void)
7014{
7015 return snd_hda_add_codec_preset(&sigmatel_list);
7016}
7017
7018static void __exit patch_sigmatel_exit(void)
7019{
7020 snd_hda_delete_codec_preset(&sigmatel_list);
7021}
7022
7023module_init(patch_sigmatel_init)
7024module_exit(patch_sigmatel_exit)