diff options
author | Jonathan Woithe <jwoithe@physics.adelaide.edu.au> | 2005-09-16 13:12:48 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-11-04 07:16:13 -0500 |
commit | a9430dd8fc232cfddcfaedde1a6a915e241366a8 (patch) | |
tree | 503b48075846759dbe689f0eb51b1d8161ba71c0 | |
parent | dfedc5f47cfd672a57923506c71b2042b33ae306 (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>
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 160 |
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 { | |||
57 | enum { | 57 | enum { |
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 | ||
76 | struct alc_spec { | 78 | struct 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 | */ | ||
294 | static 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 | |||
303 | static 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 | |||
316 | static 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 | */ | ||
2261 | static 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 | ||
2335 | static 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 | |||
2274 | static struct hda_verb alc260_init_verbs[] = { | 2359 | static 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 | */ | ||
2423 | static 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 | |||
2335 | static struct hda_pcm_stream alc260_pcm_analog_playback = { | 2474 | static 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 = { | |||
2347 | static struct hda_board_config alc260_cfg_tbl[] = { | 2486 | static 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); |