aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt1
-rw-r--r--sound/pci/hda/patch_conexant.c141
2 files changed, 79 insertions, 63 deletions
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 16ae4300c747..0caf77e59be4 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -296,6 +296,7 @@ Conexant 5066
296============= 296=============
297 laptop Basic Laptop config (default) 297 laptop Basic Laptop config (default)
298 hp-laptop HP laptops, e g G60 298 hp-laptop HP laptops, e g G60
299 asus Asus K52JU, Lenovo G560
299 dell-laptop Dell laptops 300 dell-laptop Dell laptops
300 dell-vostro Dell Vostro 301 dell-vostro Dell Vostro
301 olpc-xo-1_5 OLPC XO 1.5 302 olpc-xo-1_5 OLPC XO 1.5
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 9bb030a469cd..7e1ca43bd660 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -85,6 +85,7 @@ struct conexant_spec {
85 unsigned int auto_mic; 85 unsigned int auto_mic;
86 int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ 86 int auto_mic_ext; /* autocfg.inputs[] index for ext mic */
87 unsigned int need_dac_fix; 87 unsigned int need_dac_fix;
88 hda_nid_t slave_dig_outs[2];
88 89
89 /* capture */ 90 /* capture */
90 unsigned int num_adc_nids; 91 unsigned int num_adc_nids;
@@ -127,6 +128,7 @@ struct conexant_spec {
127 unsigned int ideapad:1; 128 unsigned int ideapad:1;
128 unsigned int thinkpad:1; 129 unsigned int thinkpad:1;
129 unsigned int hp_laptop:1; 130 unsigned int hp_laptop:1;
131 unsigned int asus:1;
130 132
131 unsigned int ext_mic_present; 133 unsigned int ext_mic_present;
132 unsigned int recording; 134 unsigned int recording;
@@ -352,6 +354,8 @@ static int conexant_build_pcms(struct hda_codec *codec)
352 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 354 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
353 spec->dig_in_nid; 355 spec->dig_in_nid;
354 } 356 }
357 if (spec->slave_dig_outs[0])
358 codec->slave_dig_outs = spec->slave_dig_outs;
355 } 359 }
356 360
357 return 0; 361 return 0;
@@ -2100,7 +2104,7 @@ static int patch_cxt5051(struct hda_codec *codec)
2100static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; 2104static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
2101static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; 2105static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
2102static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; 2106static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
2103#define CXT5066_SPDIF_OUT 0x21 2107static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
2104 2108
2105/* OLPC's microphone port is DC coupled for use with external sensors, 2109/* OLPC's microphone port is DC coupled for use with external sensors,
2106 * therefore we use a 50% mic bias in order to center the input signal with 2110 * therefore we use a 50% mic bias in order to center the input signal with
@@ -2312,6 +2316,19 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
2312 } 2316 }
2313} 2317}
2314 2318
2319
2320/* toggle input of built-in digital mic and mic jack appropriately */
2321static void cxt5066_asus_automic(struct hda_codec *codec)
2322{
2323 unsigned int present;
2324
2325 present = snd_hda_jack_detect(codec, 0x1b);
2326 snd_printdd("CXT5066: external microphone present=%d\n", present);
2327 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
2328 present ? 1 : 0);
2329}
2330
2331
2315/* toggle input of built-in digital mic and mic jack appropriately */ 2332/* toggle input of built-in digital mic and mic jack appropriately */
2316static void cxt5066_hp_laptop_automic(struct hda_codec *codec) 2333static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
2317{ 2334{
@@ -2387,79 +2404,55 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
2387 cxt5066_update_speaker(codec); 2404 cxt5066_update_speaker(codec);
2388} 2405}
2389 2406
2390/* unsolicited event for jack sensing */ 2407/* Dispatch the right mic autoswitch function */
2391static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) 2408static void cxt5066_automic(struct hda_codec *codec)
2392{ 2409{
2393 struct conexant_spec *spec = codec->spec; 2410 struct conexant_spec *spec = codec->spec;
2394 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2395 switch (res >> 26) {
2396 case CONEXANT_HP_EVENT:
2397 cxt5066_hp_automute(codec);
2398 break;
2399 case CONEXANT_MIC_EVENT:
2400 /* ignore mic events in DC mode; we're always using the jack */
2401 if (!spec->dc_enable)
2402 cxt5066_olpc_automic(codec);
2403 break;
2404 }
2405}
2406 2411
2407/* unsolicited event for jack sensing */ 2412 if (spec->dell_vostro)
2408static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
2409{
2410 snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26);
2411 switch (res >> 26) {
2412 case CONEXANT_HP_EVENT:
2413 cxt5066_hp_automute(codec);
2414 break;
2415 case CONEXANT_MIC_EVENT:
2416 cxt5066_vostro_automic(codec); 2413 cxt5066_vostro_automic(codec);
2417 break; 2414 else if (spec->ideapad)
2418 }
2419}
2420
2421/* unsolicited event for jack sensing */
2422static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
2423{
2424 snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26);
2425 switch (res >> 26) {
2426 case CONEXANT_HP_EVENT:
2427 cxt5066_hp_automute(codec);
2428 break;
2429 case CONEXANT_MIC_EVENT:
2430 cxt5066_ideapad_automic(codec); 2415 cxt5066_ideapad_automic(codec);
2431 break; 2416 else if (spec->thinkpad)
2432 } 2417 cxt5066_thinkpad_automic(codec);
2418 else if (spec->hp_laptop)
2419 cxt5066_hp_laptop_automic(codec);
2420 else if (spec->asus)
2421 cxt5066_asus_automic(codec);
2433} 2422}
2434 2423
2435/* unsolicited event for jack sensing */ 2424/* unsolicited event for jack sensing */
2436static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) 2425static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
2437{ 2426{
2438 snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); 2427 struct conexant_spec *spec = codec->spec;
2428 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2439 switch (res >> 26) { 2429 switch (res >> 26) {
2440 case CONEXANT_HP_EVENT: 2430 case CONEXANT_HP_EVENT:
2441 cxt5066_hp_automute(codec); 2431 cxt5066_hp_automute(codec);
2442 break; 2432 break;
2443 case CONEXANT_MIC_EVENT: 2433 case CONEXANT_MIC_EVENT:
2444 cxt5066_hp_laptop_automic(codec); 2434 /* ignore mic events in DC mode; we're always using the jack */
2435 if (!spec->dc_enable)
2436 cxt5066_olpc_automic(codec);
2445 break; 2437 break;
2446 } 2438 }
2447} 2439}
2448 2440
2449/* unsolicited event for jack sensing */ 2441/* unsolicited event for jack sensing */
2450static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) 2442static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
2451{ 2443{
2452 snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); 2444 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2453 switch (res >> 26) { 2445 switch (res >> 26) {
2454 case CONEXANT_HP_EVENT: 2446 case CONEXANT_HP_EVENT:
2455 cxt5066_hp_automute(codec); 2447 cxt5066_hp_automute(codec);
2456 break; 2448 break;
2457 case CONEXANT_MIC_EVENT: 2449 case CONEXANT_MIC_EVENT:
2458 cxt5066_thinkpad_automic(codec); 2450 cxt5066_automic(codec);
2459 break; 2451 break;
2460 } 2452 }
2461} 2453}
2462 2454
2455
2463static const struct hda_input_mux cxt5066_analog_mic_boost = { 2456static const struct hda_input_mux cxt5066_analog_mic_boost = {
2464 .num_items = 5, 2457 .num_items = 5,
2465 .items = { 2458 .items = {
@@ -2633,6 +2626,27 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
2633 spec->recording = 0; 2626 spec->recording = 0;
2634} 2627}
2635 2628
2629static void conexant_check_dig_outs(struct hda_codec *codec,
2630 hda_nid_t *dig_pins,
2631 int num_pins)
2632{
2633 struct conexant_spec *spec = codec->spec;
2634 hda_nid_t *nid_loc = &spec->multiout.dig_out_nid;
2635 int i;
2636
2637 for (i = 0; i < num_pins; i++, dig_pins++) {
2638 unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins);
2639 if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE)
2640 continue;
2641 if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1)
2642 continue;
2643 if (spec->slave_dig_outs[0])
2644 nid_loc++;
2645 else
2646 nid_loc = spec->slave_dig_outs;
2647 }
2648}
2649
2636static struct hda_input_mux cxt5066_capture_source = { 2650static struct hda_input_mux cxt5066_capture_source = {
2637 .num_items = 4, 2651 .num_items = 4,
2638 .items = { 2652 .items = {
@@ -3039,20 +3053,11 @@ static struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
3039/* initialize jack-sensing, too */ 3053/* initialize jack-sensing, too */
3040static int cxt5066_init(struct hda_codec *codec) 3054static int cxt5066_init(struct hda_codec *codec)
3041{ 3055{
3042 struct conexant_spec *spec = codec->spec;
3043
3044 snd_printdd("CXT5066: init\n"); 3056 snd_printdd("CXT5066: init\n");
3045 conexant_init(codec); 3057 conexant_init(codec);
3046 if (codec->patch_ops.unsol_event) { 3058 if (codec->patch_ops.unsol_event) {
3047 cxt5066_hp_automute(codec); 3059 cxt5066_hp_automute(codec);
3048 if (spec->dell_vostro) 3060 cxt5066_automic(codec);
3049 cxt5066_vostro_automic(codec);
3050 else if (spec->ideapad)
3051 cxt5066_ideapad_automic(codec);
3052 else if (spec->thinkpad)
3053 cxt5066_thinkpad_automic(codec);
3054 else if (spec->hp_laptop)
3055 cxt5066_hp_laptop_automic(codec);
3056 } 3061 }
3057 cxt5066_set_mic_boost(codec); 3062 cxt5066_set_mic_boost(codec);
3058 return 0; 3063 return 0;
@@ -3080,6 +3085,7 @@ enum {
3080 CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ 3085 CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
3081 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ 3086 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
3082 CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ 3087 CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
3088 CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
3083 CXT5066_HP_LAPTOP, /* HP Laptop */ 3089 CXT5066_HP_LAPTOP, /* HP Laptop */
3084 CXT5066_MODELS 3090 CXT5066_MODELS
3085}; 3091};
@@ -3091,6 +3097,7 @@ static const char * const cxt5066_models[CXT5066_MODELS] = {
3091 [CXT5066_DELL_VOSTRO] = "dell-vostro", 3097 [CXT5066_DELL_VOSTRO] = "dell-vostro",
3092 [CXT5066_IDEAPAD] = "ideapad", 3098 [CXT5066_IDEAPAD] = "ideapad",
3093 [CXT5066_THINKPAD] = "thinkpad", 3099 [CXT5066_THINKPAD] = "thinkpad",
3100 [CXT5066_ASUS] = "asus",
3094 [CXT5066_HP_LAPTOP] = "hp-laptop", 3101 [CXT5066_HP_LAPTOP] = "hp-laptop",
3095}; 3102};
3096 3103
@@ -3102,7 +3109,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
3102 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), 3109 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
3103 SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), 3110 SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
3104 SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), 3111 SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
3105 SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP), 3112 SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS),
3113 SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
3114 SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
3106 SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), 3115 SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
3107 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), 3116 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
3108 SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), 3117 SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
@@ -3111,7 +3120,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
3111 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), 3120 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
3112 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), 3121 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
3113 SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), 3122 SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
3123 SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
3114 SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), 3124 SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
3125 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
3115 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ 3126 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
3116 {} 3127 {}
3117}; 3128};
@@ -3133,7 +3144,8 @@ static int patch_cxt5066(struct hda_codec *codec)
3133 spec->multiout.max_channels = 2; 3144 spec->multiout.max_channels = 2;
3134 spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); 3145 spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
3135 spec->multiout.dac_nids = cxt5066_dac_nids; 3146 spec->multiout.dac_nids = cxt5066_dac_nids;
3136 spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; 3147 conexant_check_dig_outs(codec, cxt5066_digout_pin_nids,
3148 ARRAY_SIZE(cxt5066_digout_pin_nids));
3137 spec->num_adc_nids = 1; 3149 spec->num_adc_nids = 1;
3138 spec->adc_nids = cxt5066_adc_nids; 3150 spec->adc_nids = cxt5066_adc_nids;
3139 spec->capsrc_nids = cxt5066_capsrc_nids; 3151 spec->capsrc_nids = cxt5066_capsrc_nids;
@@ -3167,17 +3179,20 @@ static int patch_cxt5066(struct hda_codec *codec)
3167 spec->num_init_verbs++; 3179 spec->num_init_verbs++;
3168 spec->dell_automute = 1; 3180 spec->dell_automute = 1;
3169 break; 3181 break;
3182 case CXT5066_ASUS:
3170 case CXT5066_HP_LAPTOP: 3183 case CXT5066_HP_LAPTOP:
3171 codec->patch_ops.init = cxt5066_init; 3184 codec->patch_ops.init = cxt5066_init;
3172 codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; 3185 codec->patch_ops.unsol_event = cxt5066_unsol_event;
3173 spec->init_verbs[spec->num_init_verbs] = 3186 spec->init_verbs[spec->num_init_verbs] =
3174 cxt5066_init_verbs_hp_laptop; 3187 cxt5066_init_verbs_hp_laptop;
3175 spec->num_init_verbs++; 3188 spec->num_init_verbs++;
3176 spec->hp_laptop = 1; 3189 spec->hp_laptop = board_config == CXT5066_HP_LAPTOP;
3190 spec->asus = board_config == CXT5066_ASUS;
3177 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3191 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3178 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3192 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3179 /* no S/PDIF out */ 3193 /* no S/PDIF out */
3180 spec->multiout.dig_out_nid = 0; 3194 if (board_config == CXT5066_HP_LAPTOP)
3195 spec->multiout.dig_out_nid = 0;
3181 /* input source automatically selected */ 3196 /* input source automatically selected */
3182 spec->input_mux = NULL; 3197 spec->input_mux = NULL;
3183 spec->port_d_mode = 0; 3198 spec->port_d_mode = 0;
@@ -3207,7 +3222,7 @@ static int patch_cxt5066(struct hda_codec *codec)
3207 break; 3222 break;
3208 case CXT5066_DELL_VOSTRO: 3223 case CXT5066_DELL_VOSTRO:
3209 codec->patch_ops.init = cxt5066_init; 3224 codec->patch_ops.init = cxt5066_init;
3210 codec->patch_ops.unsol_event = cxt5066_vostro_event; 3225 codec->patch_ops.unsol_event = cxt5066_unsol_event;
3211 spec->init_verbs[0] = cxt5066_init_verbs_vostro; 3226 spec->init_verbs[0] = cxt5066_init_verbs_vostro;
3212 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 3227 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
3213 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3228 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
@@ -3224,7 +3239,7 @@ static int patch_cxt5066(struct hda_codec *codec)
3224 break; 3239 break;
3225 case CXT5066_IDEAPAD: 3240 case CXT5066_IDEAPAD:
3226 codec->patch_ops.init = cxt5066_init; 3241 codec->patch_ops.init = cxt5066_init;
3227 codec->patch_ops.unsol_event = cxt5066_ideapad_event; 3242 codec->patch_ops.unsol_event = cxt5066_unsol_event;
3228 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3243 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3229 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3244 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3230 spec->init_verbs[0] = cxt5066_init_verbs_ideapad; 3245 spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
@@ -3240,7 +3255,7 @@ static int patch_cxt5066(struct hda_codec *codec)
3240 break; 3255 break;
3241 case CXT5066_THINKPAD: 3256 case CXT5066_THINKPAD:
3242 codec->patch_ops.init = cxt5066_init; 3257 codec->patch_ops.init = cxt5066_init;
3243 codec->patch_ops.unsol_event = cxt5066_thinkpad_event; 3258 codec->patch_ops.unsol_event = cxt5066_unsol_event;
3244 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3259 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3245 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3260 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3246 spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; 3261 spec->init_verbs[0] = cxt5066_init_verbs_thinkpad;