aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_realtek.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-03-03 10:47:17 -0500
committerJaroslav Kysela <perex@suse.cz>2006-03-22 04:34:28 -0500
commitae6b813a4dbba2713df497c032798b845289653f (patch)
tree2806de741935a48d56b197c7ce1568ea755f0fbd /sound/pci/hda/patch_realtek.c
parentb3b0abe11d606fa2344793edd3d69b98b430b0d4 (diff)
[ALSA] hda-codec - Add lg model for LG laptop
Modules: Documentation,HDA Codec driver Added a new model 'lg' for LG laptop (m1 express dual) with ALC880 codec. Also clean up the initialization/unsol_event hooks in patch_realtek.c. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r--sound/pci/hda/patch_realtek.c220
1 files changed, 192 insertions, 28 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 5de754a51fc7..fcab766862d4 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -51,6 +51,7 @@ enum {
51 ALC880_UNIWILL_DIG, 51 ALC880_UNIWILL_DIG,
52 ALC880_CLEVO, 52 ALC880_CLEVO,
53 ALC880_TCL_S700, 53 ALC880_TCL_S700,
54 ALC880_LG,
54#ifdef CONFIG_SND_DEBUG 55#ifdef CONFIG_SND_DEBUG
55 ALC880_TEST, 56 ALC880_TEST,
56#endif 57#endif
@@ -147,6 +148,10 @@ struct alc_spec {
147 struct hda_input_mux private_imux; 148 struct hda_input_mux private_imux;
148 hda_nid_t private_dac_nids[5]; 149 hda_nid_t private_dac_nids[5];
149 150
151 /* hooks */
152 void (*init_hook)(struct hda_codec *codec);
153 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
154
150 /* for pin sensing */ 155 /* for pin sensing */
151 unsigned int sense_updated: 1; 156 unsigned int sense_updated: 1;
152 unsigned int jack_present: 1; 157 unsigned int jack_present: 1;
@@ -168,6 +173,8 @@ struct alc_config_preset {
168 unsigned int num_channel_mode; 173 unsigned int num_channel_mode;
169 const struct hda_channel_mode *channel_mode; 174 const struct hda_channel_mode *channel_mode;
170 const struct hda_input_mux *input_mux; 175 const struct hda_input_mux *input_mux;
176 void (*unsol_event)(struct hda_codec *, unsigned int);
177 void (*init_hook)(struct hda_codec *);
171}; 178};
172 179
173 180
@@ -481,6 +488,9 @@ static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *
481 spec->num_adc_nids = preset->num_adc_nids; 488 spec->num_adc_nids = preset->num_adc_nids;
482 spec->adc_nids = preset->adc_nids; 489 spec->adc_nids = preset->adc_nids;
483 spec->dig_in_nid = preset->dig_in_nid; 490 spec->dig_in_nid = preset->dig_in_nid;
491
492 spec->unsol_event = preset->unsol_event;
493 spec->init_hook = preset->init_hook;
484} 494}
485 495
486/* 496/*
@@ -1283,6 +1293,141 @@ static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
1283}; 1293};
1284 1294
1285/* 1295/*
1296 * LG m1 express dual
1297 *
1298 * Pin assignment:
1299 * Rear Line-In/Out (blue): 0x14
1300 * Build-in Mic-In: 0x15
1301 * Speaker-out: 0x17
1302 * HP-Out (green): 0x1b
1303 * Mic-In/Out (red): 0x19
1304 * SPDIF-Out: 0x1e
1305 */
1306
1307/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
1308static hda_nid_t alc880_lg_dac_nids[3] = {
1309 0x05, 0x02, 0x03
1310};
1311
1312/* seems analog CD is not working */
1313static struct hda_input_mux alc880_lg_capture_source = {
1314 .num_items = 3,
1315 .items = {
1316 { "Mic", 0x1 },
1317 { "Line", 0x5 },
1318 { "Internal Mic", 0x6 },
1319 },
1320};
1321
1322/* 2,4,6 channel modes */
1323static struct hda_verb alc880_lg_ch2_init[] = {
1324 /* set line-in and mic-in to input */
1325 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1326 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1327 { }
1328};
1329
1330static struct hda_verb alc880_lg_ch4_init[] = {
1331 /* set line-in to out and mic-in to input */
1332 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
1333 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1334 { }
1335};
1336
1337static struct hda_verb alc880_lg_ch6_init[] = {
1338 /* set line-in and mic-in to output */
1339 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
1340 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
1341 { }
1342};
1343
1344static struct hda_channel_mode alc880_lg_ch_modes[3] = {
1345 { 2, alc880_lg_ch2_init },
1346 { 4, alc880_lg_ch4_init },
1347 { 6, alc880_lg_ch6_init },
1348};
1349
1350static struct snd_kcontrol_new alc880_lg_mixer[] = {
1351 /* FIXME: it's not really "master" but front channels */
1352 HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1353 HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT),
1354 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1355 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
1356 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
1357 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
1358 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
1359 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
1360 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1361 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1362 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
1363 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
1364 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
1365 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
1366 {
1367 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1368 .name = "Channel Mode",
1369 .info = alc_ch_mode_info,
1370 .get = alc_ch_mode_get,
1371 .put = alc_ch_mode_put,
1372 },
1373 { } /* end */
1374};
1375
1376static struct hda_verb alc880_lg_init_verbs[] = {
1377 /* set capture source to mic-in */
1378 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1379 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1380 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1381 /* mute all amp mixer inputs */
1382 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
1383 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
1384 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
1385 /* line-in to input */
1386 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1387 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1388 /* built-in mic */
1389 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1390 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1391 /* speaker-out */
1392 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1393 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1394 /* mic-in to input */
1395 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1396 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1397 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1398 /* HP-out */
1399 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
1400 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1401 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1402 /* jack sense */
1403 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
1404 { }
1405};
1406
1407/* toggle speaker-output according to the hp-jack state */
1408static void alc880_lg_automute(struct hda_codec *codec)
1409{
1410 unsigned int present;
1411
1412 present = snd_hda_codec_read(codec, 0x1b, 0,
1413 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1414 snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0,
1415 0x80, present ? 0x80 : 0);
1416 snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0,
1417 0x80, present ? 0x80 : 0);
1418}
1419
1420static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
1421{
1422 /* Looks like the unsol event is incompatible with the standard
1423 * definition. 4bit tag is placed at 28 bit!
1424 */
1425 if ((res >> 28) == 0x01)
1426 alc880_lg_automute(codec);
1427}
1428
1429/*
1430 * Common callbacks
1286 */ 1431 */
1287 1432
1288static int alc_init(struct hda_codec *codec) 1433static int alc_init(struct hda_codec *codec)
@@ -1292,9 +1437,21 @@ static int alc_init(struct hda_codec *codec)
1292 1437
1293 for (i = 0; i < spec->num_init_verbs; i++) 1438 for (i = 0; i < spec->num_init_verbs; i++)
1294 snd_hda_sequence_write(codec, spec->init_verbs[i]); 1439 snd_hda_sequence_write(codec, spec->init_verbs[i]);
1440
1441 if (spec->init_hook)
1442 spec->init_hook(codec);
1443
1295 return 0; 1444 return 0;
1296} 1445}
1297 1446
1447static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
1448{
1449 struct alc_spec *spec = codec->spec;
1450
1451 if (spec->unsol_event)
1452 spec->unsol_event(codec, res);
1453}
1454
1298#ifdef CONFIG_PM 1455#ifdef CONFIG_PM
1299/* 1456/*
1300 * resume 1457 * resume
@@ -1531,6 +1688,7 @@ static struct hda_codec_ops alc_patch_ops = {
1531 .build_pcms = alc_build_pcms, 1688 .build_pcms = alc_build_pcms,
1532 .init = alc_init, 1689 .init = alc_init,
1533 .free = alc_free, 1690 .free = alc_free,
1691 .unsol_event = alc_unsol_event,
1534#ifdef CONFIG_PM 1692#ifdef CONFIG_PM
1535 .resume = alc_resume, 1693 .resume = alc_resume,
1536#endif 1694#endif
@@ -1549,13 +1707,15 @@ static hda_nid_t alc880_test_dac_nids[4] = {
1549}; 1707};
1550 1708
1551static struct hda_input_mux alc880_test_capture_source = { 1709static struct hda_input_mux alc880_test_capture_source = {
1552 .num_items = 5, 1710 .num_items = 7,
1553 .items = { 1711 .items = {
1554 { "In-1", 0x0 }, 1712 { "In-1", 0x0 },
1555 { "In-2", 0x1 }, 1713 { "In-2", 0x1 },
1556 { "In-3", 0x2 }, 1714 { "In-3", 0x2 },
1557 { "In-4", 0x3 }, 1715 { "In-4", 0x3 },
1558 { "CD", 0x4 }, 1716 { "CD", 0x4 },
1717 { "Front", 0x5 },
1718 { "Surround", 0x6 },
1559 }, 1719 },
1560}; 1720};
1561 1721
@@ -1911,6 +2071,9 @@ static struct hda_board_config alc880_cfg_tbl[] = {
1911 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, 2071 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
1912 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 }, 2072 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
1913 2073
2074 { .modelname = "lg", .config = ALC880_LG },
2075 { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
2076
1914#ifdef CONFIG_SND_DEBUG 2077#ifdef CONFIG_SND_DEBUG
1915 { .modelname = "test", .config = ALC880_TEST }, 2078 { .modelname = "test", .config = ALC880_TEST },
1916#endif 2079#endif
@@ -2088,6 +2251,19 @@ static struct alc_config_preset alc880_presets[] = {
2088 .channel_mode = alc880_threestack_modes, 2251 .channel_mode = alc880_threestack_modes,
2089 .input_mux = &alc880_capture_source, 2252 .input_mux = &alc880_capture_source,
2090 }, 2253 },
2254 [ALC880_LG] = {
2255 .mixers = { alc880_lg_mixer },
2256 .init_verbs = { alc880_volume_init_verbs,
2257 alc880_lg_init_verbs },
2258 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
2259 .dac_nids = alc880_lg_dac_nids,
2260 .dig_out_nid = ALC880_DIGOUT_NID,
2261 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
2262 .channel_mode = alc880_lg_ch_modes,
2263 .input_mux = &alc880_lg_capture_source,
2264 .unsol_event = alc880_lg_unsol_event,
2265 .init_hook = alc880_lg_automute,
2266 },
2091#ifdef CONFIG_SND_DEBUG 2267#ifdef CONFIG_SND_DEBUG
2092 [ALC880_TEST] = { 2268 [ALC880_TEST] = {
2093 .mixers = { alc880_test_mixer }, 2269 .mixers = { alc880_test_mixer },
@@ -2427,14 +2603,12 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
2427 return 1; 2603 return 1;
2428} 2604}
2429 2605
2430/* init callback for auto-configuration model -- overriding the default init */ 2606/* additional initialization for auto-configuration model */
2431static int alc880_auto_init(struct hda_codec *codec) 2607static void alc880_auto_init(struct hda_codec *codec)
2432{ 2608{
2433 alc_init(codec);
2434 alc880_auto_init_multi_out(codec); 2609 alc880_auto_init_multi_out(codec);
2435 alc880_auto_init_extra_out(codec); 2610 alc880_auto_init_extra_out(codec);
2436 alc880_auto_init_analog_input(codec); 2611 alc880_auto_init_analog_input(codec);
2437 return 0;
2438} 2612}
2439 2613
2440/* 2614/*
@@ -2501,7 +2675,7 @@ static int patch_alc880(struct hda_codec *codec)
2501 2675
2502 codec->patch_ops = alc_patch_ops; 2676 codec->patch_ops = alc_patch_ops;
2503 if (board_config == ALC880_AUTO) 2677 if (board_config == ALC880_AUTO)
2504 codec->patch_ops.init = alc880_auto_init; 2678 spec->init_hook = alc880_auto_init;
2505 2679
2506 return 0; 2680 return 0;
2507} 2681}
@@ -3456,13 +3630,11 @@ static int alc260_parse_auto_config(struct hda_codec *codec)
3456 return 1; 3630 return 1;
3457} 3631}
3458 3632
3459/* init callback for auto-configuration model -- overriding the default init */ 3633/* additional initialization for auto-configuration model */
3460static int alc260_auto_init(struct hda_codec *codec) 3634static void alc260_auto_init(struct hda_codec *codec)
3461{ 3635{
3462 alc_init(codec);
3463 alc260_auto_init_multi_out(codec); 3636 alc260_auto_init_multi_out(codec);
3464 alc260_auto_init_analog_input(codec); 3637 alc260_auto_init_analog_input(codec);
3465 return 0;
3466} 3638}
3467 3639
3468/* 3640/*
@@ -3614,7 +3786,7 @@ static int patch_alc260(struct hda_codec *codec)
3614 3786
3615 codec->patch_ops = alc_patch_ops; 3787 codec->patch_ops = alc_patch_ops;
3616 if (board_config == ALC260_AUTO) 3788 if (board_config == ALC260_AUTO)
3617 codec->patch_ops.init = alc260_auto_init; 3789 spec->init_hook = alc260_auto_init;
3618 3790
3619 return 0; 3791 return 0;
3620} 3792}
@@ -4089,14 +4261,12 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
4089 return err; 4261 return err;
4090} 4262}
4091 4263
4092/* init callback for auto-configuration model -- overriding the default init */ 4264/* additional initialization for auto-configuration model */
4093static int alc882_auto_init(struct hda_codec *codec) 4265static void alc882_auto_init(struct hda_codec *codec)
4094{ 4266{
4095 alc_init(codec);
4096 alc882_auto_init_multi_out(codec); 4267 alc882_auto_init_multi_out(codec);
4097 alc882_auto_init_hp_out(codec); 4268 alc882_auto_init_hp_out(codec);
4098 alc882_auto_init_analog_input(codec); 4269 alc882_auto_init_analog_input(codec);
4099 return 0;
4100} 4270}
4101 4271
4102/* 4272/*
@@ -4163,7 +4333,7 @@ static int patch_alc882(struct hda_codec *codec)
4163 4333
4164 codec->patch_ops = alc_patch_ops; 4334 codec->patch_ops = alc_patch_ops;
4165 if (board_config == ALC882_AUTO) 4335 if (board_config == ALC882_AUTO)
4166 codec->patch_ops.init = alc882_auto_init; 4336 spec->init_hook = alc882_auto_init;
4167 4337
4168 return 0; 4338 return 0;
4169} 4339}
@@ -4583,13 +4753,11 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
4583 4753
4584 4754
4585/* init callback for auto-configuration model -- overriding the default init */ 4755/* init callback for auto-configuration model -- overriding the default init */
4586static int alc262_auto_init(struct hda_codec *codec) 4756static void alc262_auto_init(struct hda_codec *codec)
4587{ 4757{
4588 alc_init(codec);
4589 alc262_auto_init_multi_out(codec); 4758 alc262_auto_init_multi_out(codec);
4590 alc262_auto_init_hp_out(codec); 4759 alc262_auto_init_hp_out(codec);
4591 alc262_auto_init_analog_input(codec); 4760 alc262_auto_init_analog_input(codec);
4592 return 0;
4593} 4761}
4594 4762
4595/* 4763/*
@@ -4624,6 +4792,7 @@ static struct alc_config_preset alc262_presets[] = {
4624 .num_channel_mode = ARRAY_SIZE(alc262_modes), 4792 .num_channel_mode = ARRAY_SIZE(alc262_modes),
4625 .channel_mode = alc262_modes, 4793 .channel_mode = alc262_modes,
4626 .input_mux = &alc262_fujitsu_capture_source, 4794 .input_mux = &alc262_fujitsu_capture_source,
4795 .unsol_event = alc262_fujitsu_unsol_event,
4627 }, 4796 },
4628}; 4797};
4629 4798
@@ -4698,9 +4867,7 @@ static int patch_alc262(struct hda_codec *codec)
4698 4867
4699 codec->patch_ops = alc_patch_ops; 4868 codec->patch_ops = alc_patch_ops;
4700 if (board_config == ALC262_AUTO) 4869 if (board_config == ALC262_AUTO)
4701 codec->patch_ops.init = alc262_auto_init; 4870 spec->init_hook = alc262_auto_init;
4702 if (board_config == ALC262_FUJITSU)
4703 codec->patch_ops.unsol_event = alc262_fujitsu_unsol_event;
4704 4871
4705 return 0; 4872 return 0;
4706} 4873}
@@ -5262,15 +5429,12 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
5262 return 1; 5429 return 1;
5263} 5430}
5264 5431
5265/* init callback for auto-configuration model -- overriding the default init */ 5432/* additional initialization for auto-configuration model */
5266static int alc861_auto_init(struct hda_codec *codec) 5433static void alc861_auto_init(struct hda_codec *codec)
5267{ 5434{
5268 alc_init(codec);
5269 alc861_auto_init_multi_out(codec); 5435 alc861_auto_init_multi_out(codec);
5270 alc861_auto_init_hp_out(codec); 5436 alc861_auto_init_hp_out(codec);
5271 alc861_auto_init_analog_input(codec); 5437 alc861_auto_init_analog_input(codec);
5272
5273 return 0;
5274} 5438}
5275 5439
5276 5440
@@ -5368,7 +5532,7 @@ static int patch_alc861(struct hda_codec *codec)
5368 5532
5369 codec->patch_ops = alc_patch_ops; 5533 codec->patch_ops = alc_patch_ops;
5370 if (board_config == ALC861_AUTO) 5534 if (board_config == ALC861_AUTO)
5371 codec->patch_ops.init = alc861_auto_init; 5535 spec->init_hook = alc861_auto_init;
5372 5536
5373 return 0; 5537 return 0;
5374} 5538}