aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-09-15 04:07:08 -0400
committerTakashi Iwai <tiwai@suse.de>2010-09-16 01:34:55 -0400
commitf2e5731dfd3ba08b023d0626d36ccf78f54ab5e7 (patch)
treec140d2a033d40e115248367b1f6bc4afd8d29ef0 /sound/pci/hda
parentc91925db4925ba0d145478f02c093369196936e9 (diff)
ALSA: hda - Preliminary support for new Conexant audio codecs
This patch adds the preliminary support for new Conexant audio codecs with 14f1:5097, 14f1:5098, 14f1:50a1, 14f1:50a2, 14f1:50ab, 14f1:50ac, 14f1:50b8 and 14f1:50b9. Unlike other Conexant parsers, this is designed to be mostly automatic, parsing from BIOS pin configurations. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/patch_conexant.c640
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
60struct pin_dac_pair {
61 hda_nid_t pin;
62 hda_nid_t dac;
63 int type;
64};
65
60struct conexant_spec { 66struct 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
3270static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
3271
3272/* get the connection index of @nid in the widget @mux */
3273static 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 */
3290static 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 */
3313static 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 */
3332static 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 */
3349static 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 */
3401static 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 */
3429static 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
3449static 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
3464static 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 */
3472static 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 */
3480static 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 */
3490static 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
3509static 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 */
3533static 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
3549static 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
3563static 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
3579static 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
3595static 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
3606static 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
3615static 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
3658static 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
3693static 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
3706static 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
3715static 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
3748static 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
3789static 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
3821static 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
3834static 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
3846static 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
3259static struct hda_codec_preset snd_hda_preset_conexant[] = { 3873static 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");
3281MODULE_ALIAS("snd-hda-codec-id:14f15067"); 3911MODULE_ALIAS("snd-hda-codec-id:14f15067");
3282MODULE_ALIAS("snd-hda-codec-id:14f15068"); 3912MODULE_ALIAS("snd-hda-codec-id:14f15068");
3283MODULE_ALIAS("snd-hda-codec-id:14f15069"); 3913MODULE_ALIAS("snd-hda-codec-id:14f15069");
3914MODULE_ALIAS("snd-hda-codec-id:14f15097");
3915MODULE_ALIAS("snd-hda-codec-id:14f15098");
3916MODULE_ALIAS("snd-hda-codec-id:14f150a1");
3917MODULE_ALIAS("snd-hda-codec-id:14f150a2");
3918MODULE_ALIAS("snd-hda-codec-id:14f150ab");
3919MODULE_ALIAS("snd-hda-codec-id:14f150ac");
3920MODULE_ALIAS("snd-hda-codec-id:14f150b8");
3921MODULE_ALIAS("snd-hda-codec-id:14f150b9");
3284 3922
3285MODULE_LICENSE("GPL"); 3923MODULE_LICENSE("GPL");
3286MODULE_DESCRIPTION("Conexant HD-audio codec"); 3924MODULE_DESCRIPTION("Conexant HD-audio codec");