aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-08-10 12:47:44 -0400
committerTakashi Iwai <tiwai@suse.de>2009-08-10 12:47:44 -0400
commit6c8194922739138f046a4d0924519dd43b48e1f3 (patch)
treed22057966b05273af33881a46a33567c24fe966e /sound/pci/hda/patch_realtek.c
parentd5c9c8912a25550f2b6a0974667eb968fe6a316e (diff)
ALSA: hda - Add auto-mic support for Realtek codecs
Added the support for automatic mic selection via plugging for Realtek codecs (in auto-probing mode). The auto-mic mode is enabled only when one internal mic and one external mic are present. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r--sound/pci/hda/patch_realtek.c177
1 files changed, 135 insertions, 42 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b0d30fced3f5..678c2d7b7f98 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -258,6 +258,14 @@ enum {
258 ALC_INIT_GPIO3, 258 ALC_INIT_GPIO3,
259}; 259};
260 260
261struct alc_mic_route {
262 hda_nid_t pin;
263 unsigned char mux_idx;
264 unsigned char amix_idx;
265};
266
267#define MUX_IDX_UNDEF ((unsigned char)-1)
268
261struct alc_spec { 269struct alc_spec {
262 /* codec parameterization */ 270 /* codec parameterization */
263 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ 271 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
@@ -300,6 +308,8 @@ struct alc_spec {
300 unsigned int num_mux_defs; 308 unsigned int num_mux_defs;
301 const struct hda_input_mux *input_mux; 309 const struct hda_input_mux *input_mux;
302 unsigned int cur_mux[3]; 310 unsigned int cur_mux[3];
311 struct alc_mic_route ext_mic;
312 struct alc_mic_route int_mic;
303 313
304 /* channel model */ 314 /* channel model */
305 const struct hda_channel_mode *channel_mode; 315 const struct hda_channel_mode *channel_mode;
@@ -327,6 +337,7 @@ struct alc_spec {
327 unsigned int sense_updated: 1; 337 unsigned int sense_updated: 1;
328 unsigned int jack_present: 1; 338 unsigned int jack_present: 1;
329 unsigned int master_sw: 1; 339 unsigned int master_sw: 1;
340 unsigned int auto_mic:1;
330 341
331 /* other flags */ 342 /* other flags */
332 unsigned int no_analog :1; /* digital I/O only */ 343 unsigned int no_analog :1; /* digital I/O only */
@@ -963,30 +974,79 @@ static void alc_automute_pin(struct hda_codec *codec)
963 } 974 }
964} 975}
965 976
966#if 0 /* it's broken in some cases -- temporarily disabled */ 977static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
978 hda_nid_t nid)
979{
980 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
981 int i, nums;
982
983 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
984 for (i = 0; i < nums; i++)
985 if (conn[i] == nid)
986 return i;
987 return -1;
988}
989
990static int set_mic_mux_idx(struct hda_codec *codec, hda_nid_t cap,
991 struct alc_mic_route *mic)
992{
993 int idx = get_connection_index(codec, cap, mic->pin);
994 if (idx < 0)
995 return 1; /* invalid */
996 mic->mux_idx = idx;
997 return 0;
998}
999
967static void alc_mic_automute(struct hda_codec *codec) 1000static void alc_mic_automute(struct hda_codec *codec)
968{ 1001{
969 struct alc_spec *spec = codec->spec; 1002 struct alc_spec *spec = codec->spec;
970 unsigned int present; 1003 struct alc_mic_route *dead, *alive;
971 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; 1004 unsigned int present, type;
972 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; 1005 hda_nid_t cap_nid;
973 unsigned int mix_nid = spec->capsrc_nids[0]; 1006
974 unsigned int capsrc_idx_mic, capsrc_idx_fmic; 1007 if (!spec->int_mic.pin || !spec->ext_mic.pin)
975 1008 return;
976 capsrc_idx_mic = mic_nid - 0x18; 1009 if (snd_BUG_ON(!spec->adc_nids))
977 capsrc_idx_fmic = fmic_nid - 0x18; 1010 return;
978 present = snd_hda_codec_read(codec, mic_nid, 0, 1011
979 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 1012 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
980 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 1013
981 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80)); 1014 present = snd_hda_codec_read(codec, spec->ext_mic.pin, 0,
982 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 1015 AC_VERB_GET_PIN_SENSE, 0);
983 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0)); 1016 present &= AC_PINSENSE_PRESENCE;
984 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic, 1017 if (present) {
985 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); 1018 alive = &spec->ext_mic;
1019 dead = &spec->int_mic;
1020 } else {
1021 alive = &spec->int_mic;
1022 dead = &spec->ext_mic;
1023 }
1024
1025 if (alive->mux_idx == MUX_IDX_UNDEF &&
1026 set_mic_mux_idx(codec, cap_nid, alive))
1027 return;
1028 if (dead->mux_idx == MUX_IDX_UNDEF &&
1029 set_mic_mux_idx(codec, cap_nid, dead))
1030 return;
1031
1032 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1033 if (type == AC_WID_AUD_MIX) {
1034 /* Matrix-mixer style (e.g. ALC882) */
1035 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1036 alive->mux_idx,
1037 HDA_AMP_MUTE, 0);
1038 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1039 dead->mux_idx,
1040 HDA_AMP_MUTE, HDA_AMP_MUTE);
1041 } else {
1042 /* MUX style (e.g. ALC880) */
1043 snd_hda_codec_write_cache(codec, cap_nid, 0,
1044 AC_VERB_SET_CONNECT_SEL,
1045 alive->mux_idx);
1046 }
1047
1048 /* FIXME: analog mixer */
986} 1049}
987#else
988#define alc_mic_automute(codec) do {} while(0) /* NOP */
989#endif /* disabled */
990 1050
991/* unsolicited event for HP jack sensing */ 1051/* unsolicited event for HP jack sensing */
992static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) 1052static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -1142,6 +1202,55 @@ static void alc_init_auto_hp(struct hda_codec *codec)
1142 spec->unsol_event = alc_sku_unsol_event; 1202 spec->unsol_event = alc_sku_unsol_event;
1143} 1203}
1144 1204
1205static void alc_init_auto_mic(struct hda_codec *codec)
1206{
1207 struct alc_spec *spec = codec->spec;
1208 struct auto_pin_cfg *cfg = &spec->autocfg;
1209 hda_nid_t fixed, ext;
1210 int i;
1211
1212 /* there must be only two mic inputs exclusively */
1213 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
1214 if (cfg->input_pins[i])
1215 return;
1216
1217 fixed = ext = 0;
1218 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
1219 hda_nid_t nid = cfg->input_pins[i];
1220 unsigned int defcfg;
1221 if (!nid)
1222 return;
1223 defcfg = snd_hda_codec_get_pincfg(codec, nid);
1224 switch (get_defcfg_connect(defcfg)) {
1225 case AC_JACK_PORT_FIXED:
1226 if (fixed)
1227 return; /* already occupied */
1228 fixed = nid;
1229 break;
1230 case AC_JACK_PORT_COMPLEX:
1231 if (ext)
1232 return; /* already occupied */
1233 ext = nid;
1234 break;
1235 default:
1236 return; /* invalid entry */
1237 }
1238 }
1239 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1240 return; /* no unsol support */
1241 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1242 ext, fixed);
1243 spec->ext_mic.pin = ext;
1244 spec->int_mic.pin = fixed;
1245 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1246 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1247 spec->auto_mic = 1;
1248 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1249 AC_VERB_SET_UNSOLICITED_ENABLE,
1250 AC_USRSP_EN | ALC880_MIC_EVENT);
1251 spec->unsol_event = alc_sku_unsol_event;
1252}
1253
1145/* check subsystem ID and set up device-specific initialization; 1254/* check subsystem ID and set up device-specific initialization;
1146 * return 1 if initialized, 0 if invalid SSID 1255 * return 1 if initialized, 0 if invalid SSID
1147 */ 1256 */
@@ -1243,6 +1352,7 @@ do_sku:
1243 } 1352 }
1244 1353
1245 alc_init_auto_hp(codec); 1354 alc_init_auto_hp(codec);
1355 alc_init_auto_mic(codec);
1246 return 1; 1356 return 1;
1247} 1357}
1248 1358
@@ -1255,6 +1365,7 @@ static void alc_ssid_check(struct hda_codec *codec,
1255 "Enable default setup for auto mode as fallback\n"); 1365 "Enable default setup for auto mode as fallback\n");
1256 spec->init_amp = ALC_INIT_DEFAULT; 1366 spec->init_amp = ALC_INIT_DEFAULT;
1257 alc_init_auto_hp(codec); 1367 alc_init_auto_hp(codec);
1368 alc_init_auto_mic(codec);
1258 } 1369 }
1259} 1370}
1260 1371
@@ -4572,7 +4683,8 @@ static void set_capture_mixer(struct alc_spec *spec)
4572 }; 4683 };
4573 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { 4684 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4574 int mux; 4685 int mux;
4575 if (spec->input_mux && spec->input_mux->num_items > 1) 4686 if (spec->input_mux && spec->input_mux->num_items > 1 &&
4687 !spec->auto_mic)
4576 mux = 1; 4688 mux = 1;
4577 else 4689 else
4578 mux = 0; 4690 mux = 0;
@@ -17118,25 +17230,6 @@ static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
17118 return 0; 17230 return 0;
17119} 17231}
17120 17232
17121/* return the index of the src widget from the connection list of the nid.
17122 * return -1 if not found
17123 */
17124static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
17125 hda_nid_t src)
17126{
17127 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
17128 int i, conns;
17129
17130 conns = snd_hda_get_connections(codec, nid, conn_list,
17131 ARRAY_SIZE(conn_list));
17132 if (conns < 0)
17133 return -1;
17134 for (i = 0; i < conns; i++)
17135 if (conn_list[i] == src)
17136 return i;
17137 return -1;
17138}
17139
17140static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid) 17233static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
17141{ 17234{
17142 unsigned int pincap = snd_hda_query_pin_caps(codec, nid); 17235 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
@@ -17153,7 +17246,7 @@ static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
17153 17246
17154 for (i = 0; i < AUTO_PIN_LAST; i++) { 17247 for (i = 0; i < AUTO_PIN_LAST; i++) {
17155 if (alc662_is_input_pin(codec, cfg->input_pins[i])) { 17248 if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
17156 idx = alc662_input_pin_idx(codec, 0x0b, 17249 idx = get_connection_index(codec, 0x0b,
17157 cfg->input_pins[i]); 17250 cfg->input_pins[i]);
17158 if (idx >= 0) { 17251 if (idx >= 0) {
17159 err = new_analog_input(spec, cfg->input_pins[i], 17252 err = new_analog_input(spec, cfg->input_pins[i],
@@ -17162,7 +17255,7 @@ static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
17162 if (err < 0) 17255 if (err < 0)
17163 return err; 17256 return err;
17164 } 17257 }
17165 idx = alc662_input_pin_idx(codec, 0x22, 17258 idx = get_connection_index(codec, 0x22,
17166 cfg->input_pins[i]); 17259 cfg->input_pins[i]);
17167 if (idx >= 0) { 17260 if (idx >= 0) {
17168 imux->items[imux->num_items].label = 17261 imux->items[imux->num_items].label =