aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-10-25 04:40:05 -0400
committerTakashi Iwai <tiwai@suse.de>2010-10-25 04:40:05 -0400
commit506ecbca71d07fa327dd986be1682e90885678ee (patch)
treeeba675a57b0201c8f30436d08cab03c5dcd235ba /sound/pci/hda/patch_conexant.c
parentaa5c14d5c0d3e4c587db4a1b220b9c86415c538f (diff)
parent0e7adbe263f89ea2ef15b5af5e80a812b2a85025 (diff)
Merge branch 'topic/hda' into for-linus
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c651
1 files changed, 642 insertions, 9 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 972e7c453b3d..6361f752b5f3 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;
@@ -3065,7 +3075,7 @@ enum {
3065 CXT5066_LAPTOP, /* Laptops w/ EAPD support */ 3075 CXT5066_LAPTOP, /* Laptops w/ EAPD support */
3066 CXT5066_DELL_LAPTOP, /* Dell Laptop */ 3076 CXT5066_DELL_LAPTOP, /* Dell Laptop */
3067 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ 3077 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
3068 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ 3078 CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
3069 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ 3079 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
3070 CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ 3080 CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
3071 CXT5066_HP_LAPTOP, /* HP Laptop */ 3081 CXT5066_HP_LAPTOP, /* HP Laptop */
@@ -3076,25 +3086,26 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
3076 [CXT5066_LAPTOP] = "laptop", 3086 [CXT5066_LAPTOP] = "laptop",
3077 [CXT5066_DELL_LAPTOP] = "dell-laptop", 3087 [CXT5066_DELL_LAPTOP] = "dell-laptop",
3078 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", 3088 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
3079 [CXT5066_DELL_VOSTO] = "dell-vostro", 3089 [CXT5066_DELL_VOSTRO] = "dell-vostro",
3080 [CXT5066_IDEAPAD] = "ideapad", 3090 [CXT5066_IDEAPAD] = "ideapad",
3081 [CXT5066_THINKPAD] = "thinkpad", 3091 [CXT5066_THINKPAD] = "thinkpad",
3082 [CXT5066_HP_LAPTOP] = "hp-laptop", 3092 [CXT5066_HP_LAPTOP] = "hp-laptop",
3083}; 3093};
3084 3094
3085static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 3095static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
3086 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", 3096 SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
3087 CXT5066_LAPTOP), 3097 SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
3088 SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", 3098 SND_PCI_QUIRK(0x1028, 0x02f5, "Dell",
3089 CXT5066_DELL_LAPTOP), 3099 CXT5066_DELL_LAPTOP),
3090 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), 3100 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
3091 SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO),
3092 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
3093 SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), 3101 SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
3094 SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), 3102 SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
3095 SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), 3103 SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
3096 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), 3104 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
3097 SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), 3105 SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
3106 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
3107 CXT5066_LAPTOP),
3108 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
3098 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), 3109 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
3099 SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), 3110 SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
3100 SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), 3111 SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
@@ -3196,7 +3207,7 @@ static int patch_cxt5066(struct hda_codec *codec)
3196 spec->capture_prepare = cxt5066_olpc_capture_prepare; 3207 spec->capture_prepare = cxt5066_olpc_capture_prepare;
3197 spec->capture_cleanup = cxt5066_olpc_capture_cleanup; 3208 spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
3198 break; 3209 break;
3199 case CXT5066_DELL_VOSTO: 3210 case CXT5066_DELL_VOSTRO:
3200 codec->patch_ops.init = cxt5066_init; 3211 codec->patch_ops.init = cxt5066_init;
3201 codec->patch_ops.unsol_event = cxt5066_vostro_event; 3212 codec->patch_ops.unsol_event = cxt5066_vostro_event;
3202 spec->init_verbs[0] = cxt5066_init_verbs_vostro; 3213 spec->init_verbs[0] = cxt5066_init_verbs_vostro;
@@ -3254,6 +3265,604 @@ static int patch_cxt5066(struct hda_codec *codec)
3254} 3265}
3255 3266
3256/* 3267/*
3268 * Automatic parser for CX20641 & co
3269 */
3270
3271static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
3272
3273/* get the connection index of @nid in the widget @mux */
3274static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
3275 hda_nid_t nid)
3276{
3277 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
3278 int i, nums;
3279
3280 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
3281 for (i = 0; i < nums; i++)
3282 if (conn[i] == nid)
3283 return i;
3284 return -1;
3285}
3286
3287/* get an unassigned DAC from the given list.
3288 * Return the nid if found and reduce the DAC list, or return zero if
3289 * not found
3290 */
3291static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
3292 hda_nid_t *dacs, int *num_dacs)
3293{
3294 int i, nums = *num_dacs;
3295 hda_nid_t ret = 0;
3296
3297 for (i = 0; i < nums; i++) {
3298 if (get_connection_index(codec, pin, dacs[i]) >= 0) {
3299 ret = dacs[i];
3300 break;
3301 }
3302 }
3303 if (!ret)
3304 return 0;
3305 if (--nums > 0)
3306 memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t));
3307 *num_dacs = nums;
3308 return ret;
3309}
3310
3311#define MAX_AUTO_DACS 5
3312
3313/* fill analog DAC list from the widget tree */
3314static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
3315{
3316 hda_nid_t nid, end_nid;
3317 int nums = 0;
3318
3319 end_nid = codec->start_nid + codec->num_nodes;
3320 for (nid = codec->start_nid; nid < end_nid; nid++) {
3321 unsigned int wcaps = get_wcaps(codec, nid);
3322 unsigned int type = get_wcaps_type(wcaps);
3323 if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) {
3324 dacs[nums++] = nid;
3325 if (nums >= MAX_AUTO_DACS)
3326 break;
3327 }
3328 }
3329 return nums;
3330}
3331
3332/* fill pin_dac_pair list from the pin and dac list */
3333static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
3334 int num_pins, hda_nid_t *dacs, int *rest,
3335 struct pin_dac_pair *filled, int type)
3336{
3337 int i, nums;
3338
3339 nums = 0;
3340 for (i = 0; i < num_pins; i++) {
3341 filled[nums].pin = pins[i];
3342 filled[nums].type = type;
3343 filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
3344 nums++;
3345 }
3346 return nums;
3347}
3348
3349/* parse analog output paths */
3350static void cx_auto_parse_output(struct hda_codec *codec)
3351{
3352 struct conexant_spec *spec = codec->spec;
3353 struct auto_pin_cfg *cfg = &spec->autocfg;
3354 hda_nid_t dacs[MAX_AUTO_DACS];
3355 int i, j, nums, rest;
3356
3357 rest = fill_cx_auto_dacs(codec, dacs);
3358 /* parse all analog output pins */
3359 nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
3360 dacs, &rest, spec->dac_info,
3361 AUTO_PIN_LINE_OUT);
3362 nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
3363 dacs, &rest, spec->dac_info + nums,
3364 AUTO_PIN_HP_OUT);
3365 nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
3366 dacs, &rest, spec->dac_info + nums,
3367 AUTO_PIN_SPEAKER_OUT);
3368 spec->dac_info_filled = nums;
3369 /* fill multiout struct */
3370 for (i = 0; i < nums; i++) {
3371 hda_nid_t dac = spec->dac_info[i].dac;
3372 if (!dac)
3373 continue;
3374 switch (spec->dac_info[i].type) {
3375 case AUTO_PIN_LINE_OUT:
3376 spec->private_dac_nids[spec->multiout.num_dacs] = dac;
3377 spec->multiout.num_dacs++;
3378 break;
3379 case AUTO_PIN_HP_OUT:
3380 case AUTO_PIN_SPEAKER_OUT:
3381 if (!spec->multiout.hp_nid) {
3382 spec->multiout.hp_nid = dac;
3383 break;
3384 }
3385 for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++)
3386 if (!spec->multiout.extra_out_nid[j]) {
3387 spec->multiout.extra_out_nid[j] = dac;
3388 break;
3389 }
3390 break;
3391 }
3392 }
3393 spec->multiout.dac_nids = spec->private_dac_nids;
3394 spec->multiout.max_channels = nums * 2;
3395
3396 if (cfg->hp_outs > 0)
3397 spec->auto_mute = 1;
3398 spec->vmaster_nid = spec->private_dac_nids[0];
3399}
3400
3401/* auto-mute/unmute speaker and line outs according to headphone jack */
3402static void cx_auto_hp_automute(struct hda_codec *codec)
3403{
3404 struct conexant_spec *spec = codec->spec;
3405 struct auto_pin_cfg *cfg = &spec->autocfg;
3406 int i, present;
3407
3408 if (!spec->auto_mute)
3409 return;
3410 present = 0;
3411 for (i = 0; i < cfg->hp_outs; i++) {
3412 if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
3413 present = 1;
3414 break;
3415 }
3416 }
3417 for (i = 0; i < cfg->line_outs; i++) {
3418 snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
3419 AC_VERB_SET_PIN_WIDGET_CONTROL,
3420 present ? 0 : PIN_OUT);
3421 }
3422 for (i = 0; i < cfg->speaker_outs; i++) {
3423 snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
3424 AC_VERB_SET_PIN_WIDGET_CONTROL,
3425 present ? 0 : PIN_OUT);
3426 }
3427}
3428
3429/* automatic switch internal and external mic */
3430static void cx_auto_automic(struct hda_codec *codec)
3431{
3432 struct conexant_spec *spec = codec->spec;
3433 struct auto_pin_cfg *cfg = &spec->autocfg;
3434 struct hda_input_mux *imux = &spec->private_imux;
3435 int ext_idx = spec->auto_mic_ext;
3436
3437 if (!spec->auto_mic)
3438 return;
3439 if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
3440 snd_hda_codec_write(codec, spec->adc_nids[0], 0,
3441 AC_VERB_SET_CONNECT_SEL,
3442 imux->items[ext_idx].index);
3443 } else {
3444 snd_hda_codec_write(codec, spec->adc_nids[0], 0,
3445 AC_VERB_SET_CONNECT_SEL,
3446 imux->items[!ext_idx].index);
3447 }
3448}
3449
3450static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
3451{
3452 int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
3453 switch (res >> 26) {
3454 case CONEXANT_HP_EVENT:
3455 cx_auto_hp_automute(codec);
3456 conexant_report_jack(codec, nid);
3457 break;
3458 case CONEXANT_MIC_EVENT:
3459 cx_auto_automic(codec);
3460 conexant_report_jack(codec, nid);
3461 break;
3462 }
3463}
3464
3465/* return true if it's an internal-mic pin */
3466static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
3467{
3468 unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
3469 return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
3470 snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
3471}
3472
3473/* return true if it's an external-mic pin */
3474static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
3475{
3476 unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
3477 return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
3478 snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
3479 (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
3480}
3481
3482/* check whether the pin config is suitable for auto-mic switching;
3483 * auto-mic is enabled only when one int-mic and one-ext mic exist
3484 */
3485static void cx_auto_check_auto_mic(struct hda_codec *codec)
3486{
3487 struct conexant_spec *spec = codec->spec;
3488 struct auto_pin_cfg *cfg = &spec->autocfg;
3489
3490 if (is_ext_mic(codec, cfg->inputs[0].pin) &&
3491 is_int_mic(codec, cfg->inputs[1].pin)) {
3492 spec->auto_mic = 1;
3493 spec->auto_mic_ext = 1;
3494 return;
3495 }
3496 if (is_int_mic(codec, cfg->inputs[1].pin) &&
3497 is_ext_mic(codec, cfg->inputs[0].pin)) {
3498 spec->auto_mic = 1;
3499 spec->auto_mic_ext = 0;
3500 return;
3501 }
3502}
3503
3504static void cx_auto_parse_input(struct hda_codec *codec)
3505{
3506 struct conexant_spec *spec = codec->spec;
3507 struct auto_pin_cfg *cfg = &spec->autocfg;
3508 struct hda_input_mux *imux;
3509 int i;
3510
3511 imux = &spec->private_imux;
3512 for (i = 0; i < cfg->num_inputs; i++) {
3513 int idx = get_connection_index(codec, spec->adc_nids[0],
3514 cfg->inputs[i].pin);
3515 if (idx >= 0) {
3516 const char *label;
3517 label = hda_get_autocfg_input_label(codec, cfg, i);
3518 snd_hda_add_imux_item(imux, label, idx, NULL);
3519 }
3520 }
3521 if (imux->num_items == 2 && cfg->num_inputs == 2)
3522 cx_auto_check_auto_mic(codec);
3523 if (imux->num_items > 1 && !spec->auto_mic)
3524 spec->input_mux = imux;
3525}
3526
3527/* get digital-input audio widget corresponding to the given pin */
3528static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin)
3529{
3530 hda_nid_t nid, end_nid;
3531
3532 end_nid = codec->start_nid + codec->num_nodes;
3533 for (nid = codec->start_nid; nid < end_nid; nid++) {
3534 unsigned int wcaps = get_wcaps(codec, nid);
3535 unsigned int type = get_wcaps_type(wcaps);
3536 if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) {
3537 if (get_connection_index(codec, nid, pin) >= 0)
3538 return nid;
3539 }
3540 }
3541 return 0;
3542}
3543
3544static void cx_auto_parse_digital(struct hda_codec *codec)
3545{
3546 struct conexant_spec *spec = codec->spec;
3547 struct auto_pin_cfg *cfg = &spec->autocfg;
3548 hda_nid_t nid;
3549
3550 if (cfg->dig_outs &&
3551 snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1)
3552 spec->multiout.dig_out_nid = nid;
3553 if (cfg->dig_in_pin)
3554 spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin);
3555}
3556
3557#ifdef CONFIG_SND_HDA_INPUT_BEEP
3558static void cx_auto_parse_beep(struct hda_codec *codec)
3559{
3560 struct conexant_spec *spec = codec->spec;
3561 hda_nid_t nid, end_nid;
3562
3563 end_nid = codec->start_nid + codec->num_nodes;
3564 for (nid = codec->start_nid; nid < end_nid; nid++)
3565 if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
3566 set_beep_amp(spec, nid, 0, HDA_OUTPUT);
3567 break;
3568 }
3569}
3570#else
3571#define cx_auto_parse_beep(codec)
3572#endif
3573
3574static int cx_auto_parse_auto_config(struct hda_codec *codec)
3575{
3576 struct conexant_spec *spec = codec->spec;
3577 int err;
3578
3579 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3580 if (err < 0)
3581 return err;
3582
3583 cx_auto_parse_output(codec);
3584 cx_auto_parse_input(codec);
3585 cx_auto_parse_digital(codec);
3586 cx_auto_parse_beep(codec);
3587 return 0;
3588}
3589
3590static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
3591 hda_nid_t *pins)
3592{
3593 int i;
3594 for (i = 0; i < num_pins; i++) {
3595 if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
3596 snd_hda_codec_write(codec, pins[i], 0,
3597 AC_VERB_SET_EAPD_BTLENABLE, 0x02);
3598 }
3599}
3600
3601static void select_connection(struct hda_codec *codec, hda_nid_t pin,
3602 hda_nid_t src)
3603{
3604 int idx = get_connection_index(codec, pin, src);
3605 if (idx >= 0)
3606 snd_hda_codec_write(codec, pin, 0,
3607 AC_VERB_SET_CONNECT_SEL, idx);
3608}
3609
3610static void cx_auto_init_output(struct hda_codec *codec)
3611{
3612 struct conexant_spec *spec = codec->spec;
3613 struct auto_pin_cfg *cfg = &spec->autocfg;
3614 hda_nid_t nid;
3615 int i;
3616
3617 for (i = 0; i < spec->multiout.num_dacs; i++)
3618 snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
3619 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3620
3621 for (i = 0; i < cfg->hp_outs; i++)
3622 snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
3623 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
3624 if (spec->auto_mute) {
3625 for (i = 0; i < cfg->hp_outs; i++) {
3626 snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
3627 AC_VERB_SET_UNSOLICITED_ENABLE,
3628 AC_USRSP_EN | CONEXANT_HP_EVENT);
3629 }
3630 cx_auto_hp_automute(codec);
3631 } else {
3632 for (i = 0; i < cfg->line_outs; i++)
3633 snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
3634 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3635 for (i = 0; i < cfg->speaker_outs; i++)
3636 snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
3637 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3638 }
3639
3640 for (i = 0; i < spec->dac_info_filled; i++) {
3641 nid = spec->dac_info[i].dac;
3642 if (!nid)
3643 nid = spec->multiout.dac_nids[0];
3644 select_connection(codec, spec->dac_info[i].pin, nid);
3645 }
3646
3647 /* turn on EAPD */
3648 cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
3649 cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
3650 cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
3651}
3652
3653static void cx_auto_init_input(struct hda_codec *codec)
3654{
3655 struct conexant_spec *spec = codec->spec;
3656 struct auto_pin_cfg *cfg = &spec->autocfg;
3657 int i;
3658
3659 for (i = 0; i < spec->num_adc_nids; i++)
3660 snd_hda_codec_write(codec, spec->adc_nids[i], 0,
3661 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
3662
3663 for (i = 0; i < cfg->num_inputs; i++) {
3664 unsigned int type;
3665 if (cfg->inputs[i].type == AUTO_PIN_MIC)
3666 type = PIN_VREF80;
3667 else
3668 type = PIN_IN;
3669 snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
3670 AC_VERB_SET_PIN_WIDGET_CONTROL, type);
3671 }
3672
3673 if (spec->auto_mic) {
3674 int ext_idx = spec->auto_mic_ext;
3675 snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
3676 AC_VERB_SET_UNSOLICITED_ENABLE,
3677 AC_USRSP_EN | CONEXANT_MIC_EVENT);
3678 cx_auto_automic(codec);
3679 } else {
3680 for (i = 0; i < spec->num_adc_nids; i++) {
3681 snd_hda_codec_write(codec, spec->adc_nids[i], 0,
3682 AC_VERB_SET_CONNECT_SEL,
3683 spec->private_imux.items[0].index);
3684 }
3685 }
3686}
3687
3688static void cx_auto_init_digital(struct hda_codec *codec)
3689{
3690 struct conexant_spec *spec = codec->spec;
3691 struct auto_pin_cfg *cfg = &spec->autocfg;
3692
3693 if (spec->multiout.dig_out_nid)
3694 snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
3695 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3696 if (spec->dig_in_nid)
3697 snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
3698 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
3699}
3700
3701static int cx_auto_init(struct hda_codec *codec)
3702{
3703 /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
3704 cx_auto_init_output(codec);
3705 cx_auto_init_input(codec);
3706 cx_auto_init_digital(codec);
3707 return 0;
3708}
3709
3710static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
3711 const char *dir, int cidx,
3712 hda_nid_t nid, int hda_dir)
3713{
3714 static char name[32];
3715 static struct snd_kcontrol_new knew[] = {
3716 HDA_CODEC_VOLUME(name, 0, 0, 0),
3717 HDA_CODEC_MUTE(name, 0, 0, 0),
3718 };
3719 static char *sfx[2] = { "Volume", "Switch" };
3720 int i, err;
3721
3722 for (i = 0; i < 2; i++) {
3723 struct snd_kcontrol *kctl;
3724 knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
3725 knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
3726 knew[i].index = cidx;
3727 snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
3728 kctl = snd_ctl_new1(&knew[i], codec);
3729 if (!kctl)
3730 return -ENOMEM;
3731 err = snd_hda_ctl_add(codec, nid, kctl);
3732 if (err < 0)
3733 return err;
3734 if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
3735 break;
3736 }
3737 return 0;
3738}
3739
3740#define cx_auto_add_pb_volume(codec, nid, str, idx) \
3741 cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
3742
3743static int cx_auto_build_output_controls(struct hda_codec *codec)
3744{
3745 struct conexant_spec *spec = codec->spec;
3746 int i, err;
3747 int num_line = 0, num_hp = 0, num_spk = 0;
3748 static const char *texts[3] = { "Front", "Surround", "CLFE" };
3749
3750 if (spec->dac_info_filled == 1)
3751 return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
3752 "Master", 0);
3753 for (i = 0; i < spec->dac_info_filled; i++) {
3754 const char *label;
3755 int idx, type;
3756 if (!spec->dac_info[i].dac)
3757 continue;
3758 type = spec->dac_info[i].type;
3759 if (type == AUTO_PIN_LINE_OUT)
3760 type = spec->autocfg.line_out_type;
3761 switch (type) {
3762 case AUTO_PIN_LINE_OUT:
3763 default:
3764 label = texts[num_line++];
3765 idx = 0;
3766 break;
3767 case AUTO_PIN_HP_OUT:
3768 label = "Headphone";
3769 idx = num_hp++;
3770 break;
3771 case AUTO_PIN_SPEAKER_OUT:
3772 label = "Speaker";
3773 idx = num_spk++;
3774 break;
3775 }
3776 err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
3777 label, idx);
3778 if (err < 0)
3779 return err;
3780 }
3781 return 0;
3782}
3783
3784static int cx_auto_build_input_controls(struct hda_codec *codec)
3785{
3786 struct conexant_spec *spec = codec->spec;
3787 struct auto_pin_cfg *cfg = &spec->autocfg;
3788 static const char *prev_label;
3789 int i, err, cidx;
3790
3791 err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
3792 HDA_INPUT);
3793 if (err < 0)
3794 return err;
3795 prev_label = NULL;
3796 cidx = 0;
3797 for (i = 0; i < cfg->num_inputs; i++) {
3798 hda_nid_t nid = cfg->inputs[i].pin;
3799 const char *label;
3800 if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
3801 continue;
3802 label = hda_get_autocfg_input_label(codec, cfg, i);
3803 if (label == prev_label)
3804 cidx++;
3805 else
3806 cidx = 0;
3807 prev_label = label;
3808 err = cx_auto_add_volume(codec, label, " Capture", cidx,
3809 nid, HDA_INPUT);
3810 if (err < 0)
3811 return err;
3812 }
3813 return 0;
3814}
3815
3816static int cx_auto_build_controls(struct hda_codec *codec)
3817{
3818 int err;
3819
3820 err = cx_auto_build_output_controls(codec);
3821 if (err < 0)
3822 return err;
3823 err = cx_auto_build_input_controls(codec);
3824 if (err < 0)
3825 return err;
3826 return conexant_build_controls(codec);
3827}
3828
3829static struct hda_codec_ops cx_auto_patch_ops = {
3830 .build_controls = cx_auto_build_controls,
3831 .build_pcms = conexant_build_pcms,
3832 .init = cx_auto_init,
3833 .free = conexant_free,
3834 .unsol_event = cx_auto_unsol_event,
3835#ifdef CONFIG_SND_HDA_POWER_SAVE
3836 .suspend = conexant_suspend,
3837#endif
3838 .reboot_notify = snd_hda_shutup_pins,
3839};
3840
3841static int patch_conexant_auto(struct hda_codec *codec)
3842{
3843 struct conexant_spec *spec;
3844 int err;
3845
3846 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3847 if (!spec)
3848 return -ENOMEM;
3849 codec->spec = spec;
3850 spec->adc_nids = cx_auto_adc_nids;
3851 spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
3852 spec->capsrc_nids = spec->adc_nids;
3853 err = cx_auto_parse_auto_config(codec);
3854 if (err < 0) {
3855 kfree(codec->spec);
3856 codec->spec = NULL;
3857 return err;
3858 }
3859 codec->patch_ops = cx_auto_patch_ops;
3860 if (spec->beep_amp)
3861 snd_hda_attach_beep_device(codec, spec->beep_amp);
3862 return 0;
3863}
3864
3865/*
3257 */ 3866 */
3258 3867
3259static struct hda_codec_preset snd_hda_preset_conexant[] = { 3868static struct hda_codec_preset snd_hda_preset_conexant[] = {
@@ -3271,6 +3880,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
3271 .patch = patch_cxt5066 }, 3880 .patch = patch_cxt5066 },
3272 { .id = 0x14f15069, .name = "CX20585", 3881 { .id = 0x14f15069, .name = "CX20585",
3273 .patch = patch_cxt5066 }, 3882 .patch = patch_cxt5066 },
3883 { .id = 0x14f15097, .name = "CX20631",
3884 .patch = patch_conexant_auto },
3885 { .id = 0x14f15098, .name = "CX20632",
3886 .patch = patch_conexant_auto },
3887 { .id = 0x14f150a1, .name = "CX20641",
3888 .patch = patch_conexant_auto },
3889 { .id = 0x14f150a2, .name = "CX20642",
3890 .patch = patch_conexant_auto },
3891 { .id = 0x14f150ab, .name = "CX20651",
3892 .patch = patch_conexant_auto },
3893 { .id = 0x14f150ac, .name = "CX20652",
3894 .patch = patch_conexant_auto },
3895 { .id = 0x14f150b8, .name = "CX20664",
3896 .patch = patch_conexant_auto },
3897 { .id = 0x14f150b9, .name = "CX20665",
3898 .patch = patch_conexant_auto },
3274 {} /* terminator */ 3899 {} /* terminator */
3275}; 3900};
3276 3901
@@ -3281,6 +3906,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
3281MODULE_ALIAS("snd-hda-codec-id:14f15067"); 3906MODULE_ALIAS("snd-hda-codec-id:14f15067");
3282MODULE_ALIAS("snd-hda-codec-id:14f15068"); 3907MODULE_ALIAS("snd-hda-codec-id:14f15068");
3283MODULE_ALIAS("snd-hda-codec-id:14f15069"); 3908MODULE_ALIAS("snd-hda-codec-id:14f15069");
3909MODULE_ALIAS("snd-hda-codec-id:14f15097");
3910MODULE_ALIAS("snd-hda-codec-id:14f15098");
3911MODULE_ALIAS("snd-hda-codec-id:14f150a1");
3912MODULE_ALIAS("snd-hda-codec-id:14f150a2");
3913MODULE_ALIAS("snd-hda-codec-id:14f150ab");
3914MODULE_ALIAS("snd-hda-codec-id:14f150ac");
3915MODULE_ALIAS("snd-hda-codec-id:14f150b8");
3916MODULE_ALIAS("snd-hda-codec-id:14f150b9");
3284 3917
3285MODULE_LICENSE("GPL"); 3918MODULE_LICENSE("GPL");
3286MODULE_DESCRIPTION("Conexant HD-audio codec"); 3919MODULE_DESCRIPTION("Conexant HD-audio codec");