aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorJonathan Woithe <jwoithe@physics.adelaide.edu.au>2005-09-16 13:12:48 -0400
committerJaroslav Kysela <perex@suse.cz>2005-11-04 07:16:13 -0500
commita9430dd8fc232cfddcfaedde1a6a915e241366a8 (patch)
tree503b48075846759dbe689f0eb51b1d8161ba71c0 /sound/pci
parentdfedc5f47cfd672a57923506c71b2042b33ae306 (diff)
[ALSA] hda-codec - A new model for Fujitsu S7020
Modules: HDA Codec driver Added a new model 'fujitsu' to ALC260 config for Fujitsu S7020. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/patch_realtek.c160
1 files changed, 157 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7327deb6df9f..48356ab04579 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -57,6 +57,7 @@ enum {
57enum { 57enum {
58 ALC260_BASIC, 58 ALC260_BASIC,
59 ALC260_HP, 59 ALC260_HP,
60 ALC260_FUJITSU_S702x,
60 ALC260_MODEL_LAST /* last tag */ 61 ALC260_MODEL_LAST /* last tag */
61}; 62};
62 63
@@ -72,6 +73,7 @@ enum {
72#define PIN_VREF50 0x21 73#define PIN_VREF50 0x21
73#define PIN_OUT 0x40 74#define PIN_OUT 0x40
74#define PIN_HP 0xc0 75#define PIN_HP 0xc0
76#define PIN_HP_AMP 0x80
75 77
76struct alc_spec { 78struct alc_spec {
77 /* codec parameterization */ 79 /* codec parameterization */
@@ -284,6 +286,54 @@ static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u
284 286
285#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) 287#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir)
286 288
289/*
290 * Control of pin widget settings via the mixer. Only boolean settings are
291 * supported, so VrefEn can't be controlled using these functions as they
292 * stand.
293 */
294static int alc_pinctl_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
295{
296 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
297 uinfo->count = 1;
298 uinfo->value.integer.min = 0;
299 uinfo->value.integer.max = 1;
300 return 0;
301}
302
303static int alc_pinctl_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
304{
305 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
306 hda_nid_t nid = kcontrol->private_value & 0xffff;
307 long mask = (kcontrol->private_value >> 16) & 0xff;
308 long *valp = ucontrol->value.integer.value;
309
310 *valp = 0;
311 if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask)
312 *valp = 1;
313 return 0;
314}
315
316static int alc_pinctl_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
317{
318 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
319 hda_nid_t nid = kcontrol->private_value & 0xffff;
320 long mask = (kcontrol->private_value >> 16) & 0xff;
321 long *valp = ucontrol->value.integer.value;
322 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
323 int change = ((pinctl & mask)!=0) != *valp;
324
325 if (change)
326 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
327 *valp?(pinctl|mask):(pinctl&~mask));
328 return change;
329}
330
331#define ALC_PINCTL_SWITCH(xname, nid, mask) \
332 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
333 .info = alc_pinctl_switch_info, \
334 .get = alc_pinctl_switch_get, \
335 .put = alc_pinctl_switch_put, \
336 .private_value = (nid) | (mask<<16) }
287 337
288/* 338/*
289 * ALC880 3-stack model 339 * ALC880 3-stack model
@@ -2205,6 +2255,17 @@ static struct hda_input_mux alc260_capture_source = {
2205 }, 2255 },
2206}; 2256};
2207 2257
2258/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack
2259 * and the internal CD lines.
2260 */
2261static struct hda_input_mux alc260_fujitsu_capture_source = {
2262 .num_items = 2,
2263 .items = {
2264 { "Mic/Line", 0x0 },
2265 { "CD", 0x4 },
2266 },
2267};
2268
2208/* 2269/*
2209 * This is just place-holder, so there's something for alc_build_pcms to look 2270 * This is just place-holder, so there's something for alc_build_pcms to look
2210 * at when it calculates the maximum number of channels. ALC260 has no mixer 2271 * at when it calculates the maximum number of channels. ALC260 has no mixer
@@ -2271,6 +2332,30 @@ static snd_kcontrol_new_t alc260_hp_mixer[] = {
2271 { } /* end */ 2332 { } /* end */
2272}; 2333};
2273 2334
2335static snd_kcontrol_new_t alc260_fujitsu_mixer[] = {
2336 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2337 ALC_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
2338 ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP),
2339 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2340 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2341 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
2342 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
2343 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
2344 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
2345 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2346 ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
2347 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
2348 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
2349 {
2350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2351 .name = "Capture Source",
2352 .info = alc_mux_enum_info,
2353 .get = alc_mux_enum_get,
2354 .put = alc_mux_enum_put,
2355 },
2356 { } /* end */
2357};
2358
2274static struct hda_verb alc260_init_verbs[] = { 2359static struct hda_verb alc260_init_verbs[] = {
2275 /* Line In pin widget for input */ 2360 /* Line In pin widget for input */
2276 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2361 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
@@ -2332,6 +2417,60 @@ static struct hda_verb alc260_init_verbs[] = {
2332 { } 2417 { }
2333}; 2418};
2334 2419
2420/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
2421 * laptops.
2422 */
2423static struct hda_verb alc260_fujitsu_init_verbs[] = {
2424 /* Disable all GPIOs */
2425 {0x01, AC_VERB_SET_GPIO_MASK, 0},
2426 /* Internal speaker is connected to headphone pin */
2427 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2428 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
2429 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2430 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
2431 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2432 /* Ensure all other unused pins are disabled and muted.
2433 * Note: trying to set widget 0x15 to anything blocks all audio
2434 * output for some reason, so just leave that at the default.
2435 */
2436 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2437 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2438 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2439 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2440 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2441 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2442 /* Disable digital (SPDIF) pins */
2443 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
2444 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
2445
2446 /* Start with mixer outputs muted */
2447 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2448 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2449 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2450
2451 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
2452 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2453 /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */
2454 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2455 /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */
2456 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2457
2458 /* Mute capture amp left and right */
2459 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2460 /* Set ADC connection select to line in (on mic1 pin) */
2461 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
2462
2463 /* Mute all inputs to mixer widget (even unconnected ones) */
2464 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
2465 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
2466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
2467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
2468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
2469 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
2470 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
2471 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
2472};
2473
2335static struct hda_pcm_stream alc260_pcm_analog_playback = { 2474static struct hda_pcm_stream alc260_pcm_analog_playback = {
2336 .substreams = 1, 2475 .substreams = 1,
2337 .channels_min = 2, 2476 .channels_min = 2,
@@ -2347,6 +2486,8 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = {
2347static struct hda_board_config alc260_cfg_tbl[] = { 2486static struct hda_board_config alc260_cfg_tbl[] = {
2348 { .modelname = "hp", .config = ALC260_HP }, 2487 { .modelname = "hp", .config = ALC260_HP },
2349 { .pci_subvendor = 0x103c, .config = ALC260_HP }, 2488 { .pci_subvendor = 0x103c, .config = ALC260_HP },
2489 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x },
2490 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x },
2350 {} 2491 {}
2351}; 2492};
2352 2493
@@ -2373,14 +2514,23 @@ static int patch_alc260(struct hda_codec *codec)
2373 spec->mixers[spec->num_mixers] = alc260_hp_mixer; 2514 spec->mixers[spec->num_mixers] = alc260_hp_mixer;
2374 spec->num_mixers++; 2515 spec->num_mixers++;
2375 break; 2516 break;
2517 case ALC260_FUJITSU_S702x:
2518 spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer;
2519 spec->num_mixers++;
2520 break;
2376 default: 2521 default:
2377 spec->mixers[spec->num_mixers] = alc260_base_mixer; 2522 spec->mixers[spec->num_mixers] = alc260_base_mixer;
2378 spec->num_mixers++; 2523 spec->num_mixers++;
2379 break; 2524 break;
2380 } 2525 }
2381 2526
2382 spec->init_verbs[0] = alc260_init_verbs; 2527 if (board_config != ALC260_FUJITSU_S702x) {
2383 spec->num_init_verbs = 1; 2528 spec->init_verbs[0] = alc260_init_verbs;
2529 spec->num_init_verbs = 1;
2530 } else {
2531 spec->init_verbs[0] = alc260_fujitsu_init_verbs;
2532 spec->num_init_verbs = 1;
2533 }
2384 2534
2385 spec->channel_mode = alc260_modes; 2535 spec->channel_mode = alc260_modes;
2386 spec->num_channel_mode = ARRAY_SIZE(alc260_modes); 2536 spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
@@ -2393,7 +2543,11 @@ static int patch_alc260(struct hda_codec *codec)
2393 spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); 2543 spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids);
2394 spec->multiout.dac_nids = alc260_dac_nids; 2544 spec->multiout.dac_nids = alc260_dac_nids;
2395 2545
2396 spec->input_mux = &alc260_capture_source; 2546 if (board_config != ALC260_FUJITSU_S702x) {
2547 spec->input_mux = &alc260_capture_source;
2548 } else {
2549 spec->input_mux = &alc260_fujitsu_capture_source;
2550 }
2397 switch (board_config) { 2551 switch (board_config) {
2398 case ALC260_HP: 2552 case ALC260_HP:
2399 spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); 2553 spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids);