diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 640 |
1 files changed, 639 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 972e7c453b3d..7eee0ff65ac9 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -57,6 +57,12 @@ struct conexant_jack { | |||
57 | 57 | ||
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct pin_dac_pair { | ||
61 | hda_nid_t pin; | ||
62 | hda_nid_t dac; | ||
63 | int type; | ||
64 | }; | ||
65 | |||
60 | struct conexant_spec { | 66 | struct conexant_spec { |
61 | 67 | ||
62 | struct snd_kcontrol_new *mixers[5]; | 68 | struct snd_kcontrol_new *mixers[5]; |
@@ -77,6 +83,7 @@ struct conexant_spec { | |||
77 | unsigned int cur_eapd; | 83 | unsigned int cur_eapd; |
78 | unsigned int hp_present; | 84 | unsigned int hp_present; |
79 | unsigned int auto_mic; | 85 | unsigned int auto_mic; |
86 | int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ | ||
80 | unsigned int need_dac_fix; | 87 | unsigned int need_dac_fix; |
81 | 88 | ||
82 | /* capture */ | 89 | /* capture */ |
@@ -110,9 +117,12 @@ struct conexant_spec { | |||
110 | struct auto_pin_cfg autocfg; | 117 | struct auto_pin_cfg autocfg; |
111 | struct hda_input_mux private_imux; | 118 | struct hda_input_mux private_imux; |
112 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 119 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
120 | struct pin_dac_pair dac_info[8]; | ||
121 | int dac_info_filled; | ||
113 | 122 | ||
114 | unsigned int dell_automute; | ||
115 | unsigned int port_d_mode; | 123 | unsigned int port_d_mode; |
124 | unsigned int auto_mute:1; /* used in auto-parser */ | ||
125 | unsigned int dell_automute:1; | ||
116 | unsigned int dell_vostro:1; | 126 | unsigned int dell_vostro:1; |
117 | unsigned int ideapad:1; | 127 | unsigned int ideapad:1; |
118 | unsigned int thinkpad:1; | 128 | unsigned int thinkpad:1; |
@@ -3254,6 +3264,610 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3254 | } | 3264 | } |
3255 | 3265 | ||
3256 | /* | 3266 | /* |
3267 | * Automatic parser for CX20641 & co | ||
3268 | */ | ||
3269 | |||
3270 | static hda_nid_t cx_auto_adc_nids[] = { 0x14 }; | ||
3271 | |||
3272 | /* get the connection index of @nid in the widget @mux */ | ||
3273 | static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, | ||
3274 | hda_nid_t nid) | ||
3275 | { | ||
3276 | hda_nid_t conn[HDA_MAX_NUM_INPUTS]; | ||
3277 | int i, nums; | ||
3278 | |||
3279 | nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); | ||
3280 | for (i = 0; i < nums; i++) | ||
3281 | if (conn[i] == nid) | ||
3282 | return i; | ||
3283 | return -1; | ||
3284 | } | ||
3285 | |||
3286 | /* get an unassigned DAC from the given list. | ||
3287 | * Return the nid if found and reduce the DAC list, or return zero if | ||
3288 | * not found | ||
3289 | */ | ||
3290 | static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin, | ||
3291 | hda_nid_t *dacs, int *num_dacs) | ||
3292 | { | ||
3293 | int i, nums = *num_dacs; | ||
3294 | hda_nid_t ret = 0; | ||
3295 | |||
3296 | for (i = 0; i < nums; i++) { | ||
3297 | if (get_connection_index(codec, pin, dacs[i]) >= 0) { | ||
3298 | ret = dacs[i]; | ||
3299 | break; | ||
3300 | } | ||
3301 | } | ||
3302 | if (!ret) | ||
3303 | return 0; | ||
3304 | if (--nums > 0) | ||
3305 | memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t)); | ||
3306 | *num_dacs = nums; | ||
3307 | return ret; | ||
3308 | } | ||
3309 | |||
3310 | #define MAX_AUTO_DACS 5 | ||
3311 | |||
3312 | /* fill analog DAC list from the widget tree */ | ||
3313 | static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) | ||
3314 | { | ||
3315 | hda_nid_t nid, end_nid; | ||
3316 | int nums = 0; | ||
3317 | |||
3318 | end_nid = codec->start_nid + codec->num_nodes; | ||
3319 | for (nid = codec->start_nid; nid < end_nid; nid++) { | ||
3320 | unsigned int wcaps = get_wcaps(codec, nid); | ||
3321 | unsigned int type = get_wcaps_type(wcaps); | ||
3322 | if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) { | ||
3323 | dacs[nums++] = nid; | ||
3324 | if (nums >= MAX_AUTO_DACS) | ||
3325 | break; | ||
3326 | } | ||
3327 | } | ||
3328 | return nums; | ||
3329 | } | ||
3330 | |||
3331 | /* fill pin_dac_pair list from the pin and dac list */ | ||
3332 | static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins, | ||
3333 | int num_pins, hda_nid_t *dacs, int *rest, | ||
3334 | struct pin_dac_pair *filled, int type) | ||
3335 | { | ||
3336 | int i, nums; | ||
3337 | |||
3338 | nums = 0; | ||
3339 | for (i = 0; i < num_pins; i++) { | ||
3340 | filled[nums].pin = pins[i]; | ||
3341 | filled[nums].type = type; | ||
3342 | filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); | ||
3343 | nums++; | ||
3344 | } | ||
3345 | return nums; | ||
3346 | } | ||
3347 | |||
3348 | /* parse analog output paths */ | ||
3349 | static void cx_auto_parse_output(struct hda_codec *codec) | ||
3350 | { | ||
3351 | struct conexant_spec *spec = codec->spec; | ||
3352 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3353 | hda_nid_t dacs[MAX_AUTO_DACS]; | ||
3354 | int i, j, nums, rest; | ||
3355 | |||
3356 | rest = fill_cx_auto_dacs(codec, dacs); | ||
3357 | /* parse all analog output pins */ | ||
3358 | nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs, | ||
3359 | dacs, &rest, spec->dac_info, | ||
3360 | AUTO_PIN_LINE_OUT); | ||
3361 | nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, | ||
3362 | dacs, &rest, spec->dac_info + nums, | ||
3363 | AUTO_PIN_HP_OUT); | ||
3364 | nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, | ||
3365 | dacs, &rest, spec->dac_info + nums, | ||
3366 | AUTO_PIN_SPEAKER_OUT); | ||
3367 | spec->dac_info_filled = nums; | ||
3368 | /* fill multiout struct */ | ||
3369 | for (i = 0; i < nums; i++) { | ||
3370 | hda_nid_t dac = spec->dac_info[i].dac; | ||
3371 | if (!dac) | ||
3372 | continue; | ||
3373 | switch (spec->dac_info[i].type) { | ||
3374 | case AUTO_PIN_LINE_OUT: | ||
3375 | spec->private_dac_nids[spec->multiout.num_dacs] = dac; | ||
3376 | spec->multiout.num_dacs++; | ||
3377 | break; | ||
3378 | case AUTO_PIN_HP_OUT: | ||
3379 | case AUTO_PIN_SPEAKER_OUT: | ||
3380 | if (!spec->multiout.hp_nid) { | ||
3381 | spec->multiout.hp_nid = dac; | ||
3382 | break; | ||
3383 | } | ||
3384 | for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++) | ||
3385 | if (!spec->multiout.extra_out_nid[j]) { | ||
3386 | spec->multiout.extra_out_nid[j] = dac; | ||
3387 | break; | ||
3388 | } | ||
3389 | break; | ||
3390 | } | ||
3391 | } | ||
3392 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
3393 | spec->multiout.max_channels = nums * 2; | ||
3394 | |||
3395 | if (cfg->hp_outs > 0) | ||
3396 | spec->auto_mute = 1; | ||
3397 | spec->vmaster_nid = spec->private_dac_nids[0]; | ||
3398 | } | ||
3399 | |||
3400 | /* auto-mute/unmute speaker and line outs according to headphone jack */ | ||
3401 | static void cx_auto_hp_automute(struct hda_codec *codec) | ||
3402 | { | ||
3403 | struct conexant_spec *spec = codec->spec; | ||
3404 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3405 | int i, present; | ||
3406 | |||
3407 | if (!spec->auto_mute) | ||
3408 | return; | ||
3409 | present = 0; | ||
3410 | for (i = 0; i < cfg->hp_outs; i++) { | ||
3411 | if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) { | ||
3412 | present = 1; | ||
3413 | break; | ||
3414 | } | ||
3415 | } | ||
3416 | for (i = 0; i < cfg->line_outs; i++) { | ||
3417 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | ||
3418 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3419 | present ? 0 : PIN_OUT); | ||
3420 | } | ||
3421 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
3422 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | ||
3423 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3424 | present ? 0 : PIN_OUT); | ||
3425 | } | ||
3426 | } | ||
3427 | |||
3428 | /* automatic switch internal and external mic */ | ||
3429 | static void cx_auto_automic(struct hda_codec *codec) | ||
3430 | { | ||
3431 | struct conexant_spec *spec = codec->spec; | ||
3432 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3433 | struct hda_input_mux *imux = &spec->private_imux; | ||
3434 | int ext_idx = spec->auto_mic_ext; | ||
3435 | |||
3436 | if (!spec->auto_mic) | ||
3437 | return; | ||
3438 | if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { | ||
3439 | snd_hda_codec_write(codec, spec->adc_nids[0], 0, | ||
3440 | AC_VERB_SET_CONNECT_SEL, | ||
3441 | imux->items[ext_idx].index); | ||
3442 | } else { | ||
3443 | snd_hda_codec_write(codec, spec->adc_nids[0], 0, | ||
3444 | AC_VERB_SET_CONNECT_SEL, | ||
3445 | imux->items[!ext_idx].index); | ||
3446 | } | ||
3447 | } | ||
3448 | |||
3449 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3450 | { | ||
3451 | int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; | ||
3452 | switch (res >> 26) { | ||
3453 | case CONEXANT_HP_EVENT: | ||
3454 | cx_auto_hp_automute(codec); | ||
3455 | conexant_report_jack(codec, nid); | ||
3456 | break; | ||
3457 | case CONEXANT_MIC_EVENT: | ||
3458 | cx_auto_automic(codec); | ||
3459 | conexant_report_jack(codec, nid); | ||
3460 | break; | ||
3461 | } | ||
3462 | } | ||
3463 | |||
3464 | static int is_int_mic_conn(unsigned int def_conf) | ||
3465 | { | ||
3466 | unsigned int loc = get_defcfg_location(def_conf); | ||
3467 | return get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || | ||
3468 | (loc & 0x30) == AC_JACK_LOC_INTERNAL; | ||
3469 | } | ||
3470 | |||
3471 | /* return true if it's an internal-mic pin */ | ||
3472 | static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) | ||
3473 | { | ||
3474 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3475 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | ||
3476 | is_int_mic_conn(def_conf); | ||
3477 | } | ||
3478 | |||
3479 | /* return true if it's an external-mic pin */ | ||
3480 | static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) | ||
3481 | { | ||
3482 | unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); | ||
3483 | return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && | ||
3484 | !is_int_mic_conn(def_conf); | ||
3485 | } | ||
3486 | |||
3487 | /* check whether the pin config is suitable for auto-mic switching; | ||
3488 | * auto-mic is enabled only when one int-mic and one-ext mic exist | ||
3489 | */ | ||
3490 | static void cx_auto_check_auto_mic(struct hda_codec *codec) | ||
3491 | { | ||
3492 | struct conexant_spec *spec = codec->spec; | ||
3493 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3494 | |||
3495 | if (is_ext_mic(codec, cfg->inputs[0].pin) && | ||
3496 | is_int_mic(codec, cfg->inputs[1].pin)) { | ||
3497 | spec->auto_mic = 1; | ||
3498 | spec->auto_mic_ext = 1; | ||
3499 | return; | ||
3500 | } | ||
3501 | if (is_int_mic(codec, cfg->inputs[1].pin) && | ||
3502 | is_ext_mic(codec, cfg->inputs[0].pin)) { | ||
3503 | spec->auto_mic = 1; | ||
3504 | spec->auto_mic_ext = 0; | ||
3505 | return; | ||
3506 | } | ||
3507 | } | ||
3508 | |||
3509 | static void cx_auto_parse_input(struct hda_codec *codec) | ||
3510 | { | ||
3511 | struct conexant_spec *spec = codec->spec; | ||
3512 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3513 | struct hda_input_mux *imux; | ||
3514 | int i; | ||
3515 | |||
3516 | imux = &spec->private_imux; | ||
3517 | for (i = 0; i < cfg->num_inputs; i++) { | ||
3518 | int idx = get_connection_index(codec, spec->adc_nids[0], | ||
3519 | cfg->inputs[i].pin); | ||
3520 | if (idx >= 0) { | ||
3521 | const char *label; | ||
3522 | label = hda_get_autocfg_input_label(codec, cfg, i); | ||
3523 | snd_hda_add_imux_item(imux, label, idx, NULL); | ||
3524 | } | ||
3525 | } | ||
3526 | if (imux->num_items == 2 && cfg->num_inputs == 2) | ||
3527 | cx_auto_check_auto_mic(codec); | ||
3528 | if (imux->num_items > 1 && !spec->auto_mic) | ||
3529 | spec->input_mux = imux; | ||
3530 | } | ||
3531 | |||
3532 | /* get digital-input audio widget corresponding to the given pin */ | ||
3533 | static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin) | ||
3534 | { | ||
3535 | hda_nid_t nid, end_nid; | ||
3536 | |||
3537 | end_nid = codec->start_nid + codec->num_nodes; | ||
3538 | for (nid = codec->start_nid; nid < end_nid; nid++) { | ||
3539 | unsigned int wcaps = get_wcaps(codec, nid); | ||
3540 | unsigned int type = get_wcaps_type(wcaps); | ||
3541 | if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) { | ||
3542 | if (get_connection_index(codec, nid, pin) >= 0) | ||
3543 | return nid; | ||
3544 | } | ||
3545 | } | ||
3546 | return 0; | ||
3547 | } | ||
3548 | |||
3549 | static void cx_auto_parse_digital(struct hda_codec *codec) | ||
3550 | { | ||
3551 | struct conexant_spec *spec = codec->spec; | ||
3552 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3553 | hda_nid_t nid; | ||
3554 | |||
3555 | if (cfg->dig_outs && | ||
3556 | snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1) | ||
3557 | spec->multiout.dig_out_nid = nid; | ||
3558 | if (cfg->dig_in_pin) | ||
3559 | spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin); | ||
3560 | } | ||
3561 | |||
3562 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | ||
3563 | static void cx_auto_parse_beep(struct hda_codec *codec) | ||
3564 | { | ||
3565 | struct conexant_spec *spec = codec->spec; | ||
3566 | hda_nid_t nid, end_nid; | ||
3567 | |||
3568 | end_nid = codec->start_nid + codec->num_nodes; | ||
3569 | for (nid = codec->start_nid; nid < end_nid; nid++) | ||
3570 | if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { | ||
3571 | set_beep_amp(spec, nid, 0, HDA_OUTPUT); | ||
3572 | break; | ||
3573 | } | ||
3574 | } | ||
3575 | #else | ||
3576 | #define cx_auto_parse_beep(codec) | ||
3577 | #endif | ||
3578 | |||
3579 | static int cx_auto_parse_auto_config(struct hda_codec *codec) | ||
3580 | { | ||
3581 | struct conexant_spec *spec = codec->spec; | ||
3582 | int err; | ||
3583 | |||
3584 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
3585 | if (err < 0) | ||
3586 | return err; | ||
3587 | |||
3588 | cx_auto_parse_output(codec); | ||
3589 | cx_auto_parse_input(codec); | ||
3590 | cx_auto_parse_digital(codec); | ||
3591 | cx_auto_parse_beep(codec); | ||
3592 | return 0; | ||
3593 | } | ||
3594 | |||
3595 | static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins, | ||
3596 | hda_nid_t *pins) | ||
3597 | { | ||
3598 | int i; | ||
3599 | for (i = 0; i < num_pins; i++) { | ||
3600 | if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) | ||
3601 | snd_hda_codec_write(codec, pins[i], 0, | ||
3602 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
3603 | } | ||
3604 | } | ||
3605 | |||
3606 | static void select_connection(struct hda_codec *codec, hda_nid_t pin, | ||
3607 | hda_nid_t src) | ||
3608 | { | ||
3609 | int idx = get_connection_index(codec, pin, src); | ||
3610 | if (idx >= 0) | ||
3611 | snd_hda_codec_write(codec, pin, 0, | ||
3612 | AC_VERB_SET_CONNECT_SEL, idx); | ||
3613 | } | ||
3614 | |||
3615 | static void cx_auto_init_output(struct hda_codec *codec) | ||
3616 | { | ||
3617 | struct conexant_spec *spec = codec->spec; | ||
3618 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3619 | hda_nid_t nid; | ||
3620 | int i; | ||
3621 | |||
3622 | for (i = 0; i < spec->multiout.num_dacs; i++) | ||
3623 | snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, | ||
3624 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | ||
3625 | |||
3626 | for (i = 0; i < cfg->hp_outs; i++) | ||
3627 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | ||
3628 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | ||
3629 | if (spec->auto_mute) { | ||
3630 | for (i = 0; i < cfg->hp_outs; i++) { | ||
3631 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | ||
3632 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3633 | AC_USRSP_EN | CONEXANT_HP_EVENT); | ||
3634 | } | ||
3635 | cx_auto_hp_automute(codec); | ||
3636 | } else { | ||
3637 | for (i = 0; i < cfg->line_outs; i++) | ||
3638 | snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, | ||
3639 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
3640 | for (i = 0; i < cfg->speaker_outs; i++) | ||
3641 | snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, | ||
3642 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
3643 | } | ||
3644 | |||
3645 | for (i = 0; i < spec->dac_info_filled; i++) { | ||
3646 | nid = spec->dac_info[i].dac; | ||
3647 | if (!nid) | ||
3648 | nid = spec->multiout.dac_nids[0]; | ||
3649 | select_connection(codec, spec->dac_info[i].pin, nid); | ||
3650 | } | ||
3651 | |||
3652 | /* turn on EAPD */ | ||
3653 | cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins); | ||
3654 | cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins); | ||
3655 | cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins); | ||
3656 | } | ||
3657 | |||
3658 | static void cx_auto_init_input(struct hda_codec *codec) | ||
3659 | { | ||
3660 | struct conexant_spec *spec = codec->spec; | ||
3661 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3662 | int i; | ||
3663 | |||
3664 | for (i = 0; i < spec->num_adc_nids; i++) | ||
3665 | snd_hda_codec_write(codec, spec->adc_nids[i], 0, | ||
3666 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)); | ||
3667 | |||
3668 | for (i = 0; i < cfg->num_inputs; i++) { | ||
3669 | unsigned int type; | ||
3670 | if (cfg->inputs[i].type == AUTO_PIN_MIC) | ||
3671 | type = PIN_VREF80; | ||
3672 | else | ||
3673 | type = PIN_IN; | ||
3674 | snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, | ||
3675 | AC_VERB_SET_PIN_WIDGET_CONTROL, type); | ||
3676 | } | ||
3677 | |||
3678 | if (spec->auto_mic) { | ||
3679 | int ext_idx = spec->auto_mic_ext; | ||
3680 | snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, | ||
3681 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3682 | AC_USRSP_EN | CONEXANT_MIC_EVENT); | ||
3683 | cx_auto_automic(codec); | ||
3684 | } else { | ||
3685 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
3686 | snd_hda_codec_write(codec, spec->adc_nids[i], 0, | ||
3687 | AC_VERB_SET_CONNECT_SEL, | ||
3688 | spec->private_imux.items[0].index); | ||
3689 | } | ||
3690 | } | ||
3691 | } | ||
3692 | |||
3693 | static void cx_auto_init_digital(struct hda_codec *codec) | ||
3694 | { | ||
3695 | struct conexant_spec *spec = codec->spec; | ||
3696 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3697 | |||
3698 | if (spec->multiout.dig_out_nid) | ||
3699 | snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0, | ||
3700 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
3701 | if (spec->dig_in_nid) | ||
3702 | snd_hda_codec_write(codec, cfg->dig_in_pin, 0, | ||
3703 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | ||
3704 | } | ||
3705 | |||
3706 | static int cx_auto_init(struct hda_codec *codec) | ||
3707 | { | ||
3708 | /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/ | ||
3709 | cx_auto_init_output(codec); | ||
3710 | cx_auto_init_input(codec); | ||
3711 | cx_auto_init_digital(codec); | ||
3712 | return 0; | ||
3713 | } | ||
3714 | |||
3715 | static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, | ||
3716 | const char *dir, int cidx, | ||
3717 | hda_nid_t nid, int hda_dir) | ||
3718 | { | ||
3719 | static char name[32]; | ||
3720 | static struct snd_kcontrol_new knew[] = { | ||
3721 | HDA_CODEC_VOLUME(name, 0, 0, 0), | ||
3722 | HDA_CODEC_MUTE(name, 0, 0, 0), | ||
3723 | }; | ||
3724 | static char *sfx[2] = { "Volume", "Switch" }; | ||
3725 | int i, err; | ||
3726 | |||
3727 | for (i = 0; i < 2; i++) { | ||
3728 | struct snd_kcontrol *kctl; | ||
3729 | knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir); | ||
3730 | knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; | ||
3731 | knew[i].index = cidx; | ||
3732 | snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); | ||
3733 | kctl = snd_ctl_new1(&knew[i], codec); | ||
3734 | if (!kctl) | ||
3735 | return -ENOMEM; | ||
3736 | err = snd_hda_ctl_add(codec, nid, kctl); | ||
3737 | if (err < 0) | ||
3738 | return err; | ||
3739 | if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) | ||
3740 | break; | ||
3741 | } | ||
3742 | return 0; | ||
3743 | } | ||
3744 | |||
3745 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ | ||
3746 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) | ||
3747 | |||
3748 | static int cx_auto_build_output_controls(struct hda_codec *codec) | ||
3749 | { | ||
3750 | struct conexant_spec *spec = codec->spec; | ||
3751 | int i, err; | ||
3752 | int num_line = 0, num_hp = 0, num_spk = 0; | ||
3753 | static const char *texts[3] = { "Front", "Surround", "CLFE" }; | ||
3754 | |||
3755 | if (spec->dac_info_filled == 1) | ||
3756 | return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, | ||
3757 | "Master", 0); | ||
3758 | for (i = 0; i < spec->dac_info_filled; i++) { | ||
3759 | const char *label; | ||
3760 | int idx, type; | ||
3761 | if (!spec->dac_info[i].dac) | ||
3762 | continue; | ||
3763 | type = spec->dac_info[i].type; | ||
3764 | if (type == AUTO_PIN_LINE_OUT) | ||
3765 | type = spec->autocfg.line_out_type; | ||
3766 | switch (type) { | ||
3767 | case AUTO_PIN_LINE_OUT: | ||
3768 | default: | ||
3769 | label = texts[num_line++]; | ||
3770 | idx = 0; | ||
3771 | break; | ||
3772 | case AUTO_PIN_HP_OUT: | ||
3773 | label = "Headphone"; | ||
3774 | idx = num_hp++; | ||
3775 | break; | ||
3776 | case AUTO_PIN_SPEAKER_OUT: | ||
3777 | label = "Speaker"; | ||
3778 | idx = num_spk++; | ||
3779 | break; | ||
3780 | } | ||
3781 | err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac, | ||
3782 | label, idx); | ||
3783 | if (err < 0) | ||
3784 | return err; | ||
3785 | } | ||
3786 | return 0; | ||
3787 | } | ||
3788 | |||
3789 | static int cx_auto_build_input_controls(struct hda_codec *codec) | ||
3790 | { | ||
3791 | struct conexant_spec *spec = codec->spec; | ||
3792 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3793 | static const char *prev_label; | ||
3794 | int i, err, cidx; | ||
3795 | |||
3796 | err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0], | ||
3797 | HDA_INPUT); | ||
3798 | if (err < 0) | ||
3799 | return err; | ||
3800 | prev_label = NULL; | ||
3801 | cidx = 0; | ||
3802 | for (i = 0; i < cfg->num_inputs; i++) { | ||
3803 | hda_nid_t nid = cfg->inputs[i].pin; | ||
3804 | const char *label; | ||
3805 | if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) | ||
3806 | continue; | ||
3807 | label = hda_get_autocfg_input_label(codec, cfg, i); | ||
3808 | if (label == prev_label) | ||
3809 | cidx++; | ||
3810 | else | ||
3811 | cidx = 0; | ||
3812 | prev_label = label; | ||
3813 | err = cx_auto_add_volume(codec, label, " Capture", cidx, | ||
3814 | nid, HDA_INPUT); | ||
3815 | if (err < 0) | ||
3816 | return err; | ||
3817 | } | ||
3818 | return 0; | ||
3819 | } | ||
3820 | |||
3821 | static int cx_auto_build_controls(struct hda_codec *codec) | ||
3822 | { | ||
3823 | int err; | ||
3824 | |||
3825 | err = cx_auto_build_output_controls(codec); | ||
3826 | if (err < 0) | ||
3827 | return err; | ||
3828 | err = cx_auto_build_input_controls(codec); | ||
3829 | if (err < 0) | ||
3830 | return err; | ||
3831 | return conexant_build_controls(codec); | ||
3832 | } | ||
3833 | |||
3834 | static struct hda_codec_ops cx_auto_patch_ops = { | ||
3835 | .build_controls = cx_auto_build_controls, | ||
3836 | .build_pcms = conexant_build_pcms, | ||
3837 | .init = cx_auto_init, | ||
3838 | .free = conexant_free, | ||
3839 | .unsol_event = cx_auto_unsol_event, | ||
3840 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
3841 | .suspend = conexant_suspend, | ||
3842 | #endif | ||
3843 | .reboot_notify = snd_hda_shutup_pins, | ||
3844 | }; | ||
3845 | |||
3846 | static int patch_conexant_auto(struct hda_codec *codec) | ||
3847 | { | ||
3848 | struct conexant_spec *spec; | ||
3849 | int err; | ||
3850 | |||
3851 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
3852 | if (!spec) | ||
3853 | return -ENOMEM; | ||
3854 | codec->spec = spec; | ||
3855 | spec->adc_nids = cx_auto_adc_nids; | ||
3856 | spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); | ||
3857 | spec->capsrc_nids = spec->adc_nids; | ||
3858 | err = cx_auto_parse_auto_config(codec); | ||
3859 | if (err < 0) { | ||
3860 | kfree(codec->spec); | ||
3861 | codec->spec = NULL; | ||
3862 | return err; | ||
3863 | } | ||
3864 | codec->patch_ops = cx_auto_patch_ops; | ||
3865 | if (spec->beep_amp) | ||
3866 | snd_hda_attach_beep_device(codec, spec->beep_amp); | ||
3867 | return 0; | ||
3868 | } | ||
3869 | |||
3870 | /* | ||
3257 | */ | 3871 | */ |
3258 | 3872 | ||
3259 | static struct hda_codec_preset snd_hda_preset_conexant[] = { | 3873 | static struct hda_codec_preset snd_hda_preset_conexant[] = { |
@@ -3271,6 +3885,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
3271 | .patch = patch_cxt5066 }, | 3885 | .patch = patch_cxt5066 }, |
3272 | { .id = 0x14f15069, .name = "CX20585", | 3886 | { .id = 0x14f15069, .name = "CX20585", |
3273 | .patch = patch_cxt5066 }, | 3887 | .patch = patch_cxt5066 }, |
3888 | { .id = 0x14f15097, .name = "CX20631", | ||
3889 | .patch = patch_conexant_auto }, | ||
3890 | { .id = 0x14f15098, .name = "CX20632", | ||
3891 | .patch = patch_conexant_auto }, | ||
3892 | { .id = 0x14f150a1, .name = "CX20641", | ||
3893 | .patch = patch_conexant_auto }, | ||
3894 | { .id = 0x14f150a2, .name = "CX20642", | ||
3895 | .patch = patch_conexant_auto }, | ||
3896 | { .id = 0x14f150ab, .name = "CX20651", | ||
3897 | .patch = patch_conexant_auto }, | ||
3898 | { .id = 0x14f150ac, .name = "CX20652", | ||
3899 | .patch = patch_conexant_auto }, | ||
3900 | { .id = 0x14f150b8, .name = "CX20664", | ||
3901 | .patch = patch_conexant_auto }, | ||
3902 | { .id = 0x14f150b9, .name = "CX20665", | ||
3903 | .patch = patch_conexant_auto }, | ||
3274 | {} /* terminator */ | 3904 | {} /* terminator */ |
3275 | }; | 3905 | }; |
3276 | 3906 | ||
@@ -3281,6 +3911,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066"); | |||
3281 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); | 3911 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); |
3282 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); | 3912 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); |
3283 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); | 3913 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); |
3914 | MODULE_ALIAS("snd-hda-codec-id:14f15097"); | ||
3915 | MODULE_ALIAS("snd-hda-codec-id:14f15098"); | ||
3916 | MODULE_ALIAS("snd-hda-codec-id:14f150a1"); | ||
3917 | MODULE_ALIAS("snd-hda-codec-id:14f150a2"); | ||
3918 | MODULE_ALIAS("snd-hda-codec-id:14f150ab"); | ||
3919 | MODULE_ALIAS("snd-hda-codec-id:14f150ac"); | ||
3920 | MODULE_ALIAS("snd-hda-codec-id:14f150b8"); | ||
3921 | MODULE_ALIAS("snd-hda-codec-id:14f150b9"); | ||
3284 | 3922 | ||
3285 | MODULE_LICENSE("GPL"); | 3923 | MODULE_LICENSE("GPL"); |
3286 | MODULE_DESCRIPTION("Conexant HD-audio codec"); | 3924 | MODULE_DESCRIPTION("Conexant HD-audio codec"); |